diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml
index 2c5bb50..0ab748d 100644
--- a/.github/workflows/test-coverage.yaml
+++ b/.github/workflows/test-coverage.yaml
@@ -4,9 +4,10 @@ on:
push:
branches: [main, master]
pull_request:
- branches: [main, master]
-name: test-coverage
+name: test-coverage.yaml
+
+permissions: read-all
jobs:
test-coverage:
@@ -15,7 +16,7 @@ jobs:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: r-lib/actions/setup-r@v2
with:
@@ -23,28 +24,39 @@ jobs:
- uses: r-lib/actions/setup-r-dependencies@v2
with:
- extra-packages: any::covr
+ extra-packages: any::covr, any::xml2
needs: coverage
- name: Test coverage
run: |
- covr::codecov(
+ cov <- covr::package_coverage(
quiet = FALSE,
clean = FALSE,
- install_path = file.path(Sys.getenv("RUNNER_TEMP"), "package")
+ install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package")
)
+ print(cov)
+ covr::to_cobertura(cov)
shell: Rscript {0}
+ - uses: codecov/codecov-action@v5
+ with:
+ # Fail if error if not on PR, or if on PR and token is given
+ fail_ci_if_error: ${{ github.event_name != 'pull_request' || secrets.CODECOV_TOKEN }}
+ files: ./cobertura.xml
+ plugins: noop
+ disable_search: true
+ token: ${{ secrets.CODECOV_TOKEN }}
+
- name: Show testthat output
if: always()
run: |
## --------------------------------------------------------------------
- find ${{ runner.temp }}/package -name 'testthat.Rout*' -exec cat '{}' \; || true
+ find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true
shell: bash
- name: Upload test results
if: failure()
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: coverage-test-failures
path: ${{ runner.temp }}/package
diff --git a/DESCRIPTION b/DESCRIPTION
index 4176923..87b3c39 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,6 +1,6 @@
Package: netz
Title: All Things Bed Nets
-Version: 1.0.4
+Version: 1.1.2
Authors@R: c(
person(
given = "Pete",
@@ -26,7 +26,7 @@ License: MIT + file LICENSE
Encoding: UTF-8
LazyData: true
Roxygen: list(markdown = TRUE)
-RoxygenNote: 7.3.2
+RoxygenNote: 7.3.3
Imports:
stats
Remotes:
diff --git a/LICENSE b/LICENSE
index 796e1f8..da837d4 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,21 +1,2 @@
-MIT License
-
-Copyright (c) 2019 MRC Centre for Outbreak Analysis and Modelling
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+YEAR: 2026
+COPYRIGHT HOLDER: YMRC Centre for Outbreak Analysis and Modelling
\ No newline at end of file
diff --git a/R/conversion.R b/R/conversion.R
index 038c399..019ab81 100644
--- a/R/conversion.R
+++ b/R/conversion.R
@@ -2,7 +2,7 @@
#'
#' @param access A single or vector of access values
#' @param type The npc to access model to use. This may be:
-#' \itemize{
+#' \describe{
#' \item{"loess"}{: a loess fit to observed access-npc data}
#' \item{"linear"}{: a linear fit to the observed access-npc data, fitted to the trend for observeation with access < 0.5}
#' }
diff --git a/R/malariasimulation.R b/R/malariasimulation.R
index da88a62..0de567c 100644
--- a/R/malariasimulation.R
+++ b/R/malariasimulation.R
@@ -1,50 +1,71 @@
-#' Estimate the malaraisimulation input distribution from usage
-#' assumes an exponentially distributed net loss function and randomly
+#' Estimate the malariasimulation input distribution from usage
+#' assumes a specified net loss function and randomly
#' correlated net distribution.
#'
+#'
#' @param usage Target usage
#' @param usage_timesteps Target usage time points
#' @param distribution_timesteps A vector of distribution time steps
#' @param distribution_lower Lower bound on distributions (default = 0)
#' @param distribution_upper Upper bound on distribution (default = 1)
-#' @param mean_retention The average duration of net retention (days)
-#'
+#' @param net_loss_function Function to calculate net retention over time.
+#' Should take time as first argument and return proportion retained.
+#' Defaults to net_loss_exp for backward compatibility.
+#' @param... Additional arguments passed to net_loss_function
+#'
+#' @details Note, the estimation works sequentially in time order, so if there
+#' are multiple distribution steps specified between target usage timestep they will
+#' be inferred sequentially. You can mange this behaviour with the `distribution_lower` and
+#' `distribution_upper` arguments.
+#'
#' @export
usage_to_model_distribution <- function(
- usage,
- usage_timesteps,
- distribution_timesteps,
- distribution_lower = rep(0, length(distribution_timesteps)),
- distribution_upper = rep(1, length(distribution_timesteps)),
- mean_retention = 365 * 5
-){
-
- if(any(distribution_lower < 0) | any(distribution_lower > 1)){
+ usage,
+ usage_timesteps,
+ distribution_timesteps,
+ distribution_lower = rep(0, length(distribution_timesteps)),
+ distribution_upper = rep(1, length(distribution_timesteps)),
+ net_loss_function = net_loss_exp,
+ ...
+) {
+ if (any(distribution_lower < 0) | any(distribution_lower > 1)) {
stop("All distribution lower values must be between 0 and 1")
}
- if(any(distribution_upper < 0) | any(distribution_upper > 1)){
+ if (any(distribution_upper < 0) | any(distribution_upper > 1)) {
stop("All distribution upper values must be between 0 and 1")
}
- if(length(distribution_lower) != length(distribution_timesteps) | length(distribution_upper) != length(distribution_timesteps)){
- stop("distribution_timesteps, distribution_lower and distribution_upper must have equal lengths")
+ if (
+ length(distribution_lower) != length(distribution_timesteps) |
+ length(distribution_upper) != length(distribution_timesteps)
+ ) {
+ stop(
+ "distribution_timesteps, distribution_lower and distribution_upper must have equal lengths"
+ )
}
- if(length(usage) != length(usage_timesteps)){
+ if (length(usage) != length(usage_timesteps)) {
stop("Usage and usage timesteps must be the same length")
}
-
- loss_rate <- 1 / mean_retention
+
distribution <- rep(0, length(distribution_timesteps))
- for(t in 1:length(distribution_timesteps)){
+ for (t in 1:length(distribution_timesteps)) {
# Usage at time point of next distribution
- put <- model_distribution_to_usage(distribution_timesteps[t], distribution, distribution_timesteps, mean_retention)
+ put <- model_distribution_to_usage(
+ usage_timesteps = distribution_timesteps[t],
+ distribution = distribution,
+ distribution_timesteps = distribution_timesteps,
+ net_loss_function = net_loss_function,
+ ...
+ )
+
# Find next target usage
- time_offset <- usage_timesteps - distribution_timesteps[t]
- if(max(time_offset) < 0){
- distribution[t] <- NA
+ time_offset <- usage_timesteps - distribution_timesteps[t]
+ if (max(time_offset) < 0) {
+ distribution[t:length(distribution_timesteps)] <- NA
+ break
} else {
nearest <- min(time_offset[time_offset >= 0])
index <- which(time_offset == nearest)
- start_point <- usage[index] / exp(-loss_rate * time_offset[index])
+ start_point <- usage[index] / net_loss_function(time_offset[index], ...)
distribution[t] <- 1 - (1 - start_point) / (1 - put)
distribution[t] <- min(distribution_upper[t], distribution[t])
distribution[t] <- max(distribution_lower[t], distribution[t])
@@ -54,44 +75,54 @@ usage_to_model_distribution <- function(
}
#' Estimate the population-level bed net usage at given times for a set of
-#' bed net distributions at given times. This assumes a constant rate of net loss
-#' (as in malariasimulation) and that recipients of multiple rounds are random.
-#'
+#' bed net distributions at given times. This assumes a specified rate of net loss
+#' and that recipients of multiple rounds are random.
+#'
#' @inheritParams usage_to_model_distribution
#' @param distribution Vector of model distribution (% of total population)
+#' @param net_loss_function Function to calculate net retention over time.
+#' Should take time as first argument and return proportion retained.
+#' @param... Additional arguments passed to net_loss_function
#'
#' @return Usage estimates at timepoints
#' @export
model_distribution_to_usage <- function(
- usage_timesteps,
- distribution,
- distribution_timesteps,
- mean_retention = 365 * 5
-){
- loss_rate <- 1 / mean_retention
-
+ usage_timesteps,
+ distribution,
+ distribution_timesteps,
+ net_loss_function = net_loss_exp,
+ ...
+) {
+ # Deal with zero distributions in inputs
+ zero_dists <- distribution == 0
+ distribution <- distribution[!zero_dists]
+ distribution_timesteps <- distribution_timesteps[!zero_dists]
+ if (length(distribution) == 0) {
+ return(rep(0, length(usage_timesteps)))
+ }
+
# Estimate the cumulative usage at distribution time points
cumulative_usage <- distribution[1]
- if(length(distribution_timesteps) > 1){
- for(t in 2:length(distribution_timesteps)){
+ if (length(distribution_timesteps) > 1) {
+ for (t in 2:length(distribution_timesteps)) {
time_offset <- distribution_timesteps[t] - distribution_timesteps[t - 1]
- remaining <- cumulative_usage[t - 1] * exp(-loss_rate * time_offset)
+ remaining <- cumulative_usage[t - 1] * net_loss_function(time_offset, ...)
cumulative_usage[t] <- 1 - (1 - remaining) * (1 - distribution[t])
}
}
-
+
# Estimate the usage at target time points
usage <- c()
- for(t in seq_along(usage_timesteps)){
+ for (t in seq_along(usage_timesteps)) {
time_offset <- usage_timesteps[t] - distribution_timesteps
- if(max(time_offset) < 0){
+ if (max(time_offset) < 0) {
usage[t] <- 0
} else {
nearest <- min(time_offset[time_offset >= 0])
index <- which(time_offset == nearest)
- usage[t] <- cumulative_usage[index] * exp(-loss_rate * time_offset[index])
+ usage[t] <- cumulative_usage[index] *
+ net_loss_function(time_offset[index], ...)
}
}
return(usage)
}
-
diff --git a/README.Rmd b/README.Rmd
index 9c3c829..03a93f2 100644
--- a/README.Rmd
+++ b/README.Rmd
@@ -17,6 +17,7 @@ knitr::opts_chunk$set(
[](https://www.repostatus.org/#active)
[](https://github.com/mrc-ide/netz/actions)
[](https://codecov.io/github/mrc-ide/netz)
+[](https://app.codecov.io/gh/mrc-ide/netz)
Netz is here to help setup bed nets in [malariasimulation](https://mrc-ide.github.io/malariasimulation/).
@@ -42,4 +43,4 @@ need to be careful that out model inputs match our desired target usage
when specifying bed nets. The schematic below will help in understanding how
each of these elements relate to one another
-
\ No newline at end of file
+
diff --git a/man/access_to_crop.Rd b/man/access_to_crop.Rd
index 7cb3b6f..630b64d 100644
--- a/man/access_to_crop.Rd
+++ b/man/access_to_crop.Rd
@@ -10,7 +10,7 @@ access_to_crop(access, type = "loess", people_per_net = 1.66856)
\item{access}{A single or vector of access values}
\item{type}{The npc to access model to use. This may be:
-\itemize{
+\describe{
\item{"loess"}{: a loess fit to observed access-npc data}
\item{"linear"}{: a linear fit to the observed access-npc data, fitted to the trend for observeation with access < 0.5}
}}
diff --git a/man/crop_to_access.Rd b/man/crop_to_access.Rd
index 833acb4..0cfec72 100644
--- a/man/crop_to_access.Rd
+++ b/man/crop_to_access.Rd
@@ -10,7 +10,7 @@ crop_to_access(crop, type = "loess", people_per_net = 1.66856)
\item{crop}{A single or vector of nets per capita}
\item{type}{The npc to access model to use. This may be:
-\itemize{
+\describe{
\item{"loess"}{: a loess fit to observed access-npc data}
\item{"linear"}{: a linear fit to the observed access-npc data, fitted to the trend for observeation with access < 0.5}
}}
diff --git a/man/model_distribution_to_usage.Rd b/man/model_distribution_to_usage.Rd
index 27e48f9..dba8d4c 100644
--- a/man/model_distribution_to_usage.Rd
+++ b/man/model_distribution_to_usage.Rd
@@ -3,14 +3,15 @@
\name{model_distribution_to_usage}
\alias{model_distribution_to_usage}
\title{Estimate the population-level bed net usage at given times for a set of
-bed net distributions at given times. This assumes a constant rate of net loss
-(as in malariasimulation) and that recipients of multiple rounds are random.}
+bed net distributions at given times. This assumes a specified rate of net loss
+and that recipients of multiple rounds are random.}
\usage{
model_distribution_to_usage(
usage_timesteps,
distribution,
distribution_timesteps,
- mean_retention = 365 * 5
+ net_loss_function = net_loss_exp,
+ ...
)
}
\arguments{
@@ -20,13 +21,16 @@ model_distribution_to_usage(
\item{distribution_timesteps}{A vector of distribution time steps}
-\item{mean_retention}{The average duration of net retention (days)}
+\item{net_loss_function}{Function to calculate net retention over time.
+Should take time as first argument and return proportion retained.}
+
+\item{...}{Additional arguments passed to net_loss_function}
}
\value{
Usage estimates at timepoints
}
\description{
Estimate the population-level bed net usage at given times for a set of
-bed net distributions at given times. This assumes a constant rate of net loss
-(as in malariasimulation) and that recipients of multiple rounds are random.
+bed net distributions at given times. This assumes a specified rate of net loss
+and that recipients of multiple rounds are random.
}
diff --git a/man/usage_to_model_distribution.Rd b/man/usage_to_model_distribution.Rd
index b21606d..b80a342 100644
--- a/man/usage_to_model_distribution.Rd
+++ b/man/usage_to_model_distribution.Rd
@@ -2,8 +2,8 @@
% Please edit documentation in R/malariasimulation.R
\name{usage_to_model_distribution}
\alias{usage_to_model_distribution}
-\title{Estimate the malaraisimulation input distribution from usage
-assumes an exponentially distributed net loss function and randomly
+\title{Estimate the malariasimulation input distribution from usage
+assumes a specified net loss function and randomly
correlated net distribution.}
\usage{
usage_to_model_distribution(
@@ -12,7 +12,8 @@ usage_to_model_distribution(
distribution_timesteps,
distribution_lower = rep(0, length(distribution_timesteps)),
distribution_upper = rep(1, length(distribution_timesteps)),
- mean_retention = 365 * 5
+ net_loss_function = net_loss_exp,
+ ...
)
}
\arguments{
@@ -26,10 +27,19 @@ usage_to_model_distribution(
\item{distribution_upper}{Upper bound on distribution (default = 1)}
-\item{mean_retention}{The average duration of net retention (days)}
+\item{net_loss_function}{Function to calculate net retention over time.
+Should take time as first argument and return proportion retained.
+Defaults to net_loss_exp for backward compatibility.}
+
+\item{...}{Additional arguments passed to net_loss_function}
}
\description{
-Estimate the malaraisimulation input distribution from usage
-assumes an exponentially distributed net loss function and randomly
+Estimate the malariasimulation input distribution from usage
+assumes a specified net loss function and randomly
correlated net distribution.
}
+\details{
+Note, the estimation works sequentially in time order, so if there
+are multiple distribution steps specified between target usage timestep they will
+be inferred sequentially.
+}
diff --git a/tests/testthat/test-malariasimulation.R b/tests/testthat/test-malariasimulation.R
index 99eef58..fb2d1d5 100644
--- a/tests/testthat/test-malariasimulation.R
+++ b/tests/testthat/test-malariasimulation.R
@@ -1,38 +1,268 @@
-test_that("malariasimulation usage fitting works", {
+test_that("malariasimulation usage fitting works - exponential model", {
tu <- 0
tut <- 365
dt <- 365
-
- expect_equal(usage_to_model_distribution(0, tut, dt), 0)
- expect_equal(usage_to_model_distribution(1, tut, dt), 1)
- expect_equal(usage_to_model_distribution(c(1,1), (1:2) * 365, (1:2) * 365), c(1, 1))
- expect_equal(usage_to_model_distribution(c(0,0), (1:2) * 365, (1:2) * 365), c(0, 0))
- expect_equal(usage_to_model_distribution(c(1,0), (1:2) * 365, (1:2) * 365), c(1, 0))
- expect_equal(usage_to_model_distribution(c(1,1), (1:2) * 365, (1:3) * 365), c(1, 1, NA))
-
- expect_error(usage_to_model_distribution(tu, tut, dt, distribution_lower = -1),
- "All distribution lower values must be between 0 and 1")
- expect_error(usage_to_model_distribution(tu, tut, dt, distribution_lower = 6),
- "All distribution lower values must be between 0 and 1")
- expect_error(usage_to_model_distribution(tu, tut, dt, distribution_upper = -1),
- "All distribution upper values must be between 0 and 1")
- expect_error(usage_to_model_distribution(tu, tut, dt, distribution_upper = 6),
- "All distribution upper values must be between 0 and 1")
-
-
- expect_error(usage_to_model_distribution(tu, tut, dt, distribution_lower = c(0.1, 0.1)),
- "distribution_timesteps, distribution_lower and distribution_upper must have equal lengths")
- expect_error(usage_to_model_distribution(tu, tut, dt, distribution_upper = c(0.1, 0.1)),
- "distribution_timesteps, distribution_lower and distribution_upper must have equal lengths")
-
- expect_error(usage_to_model_distribution(tu, c(tut, tut), dt),
- "Usage and usage timesteps must be the same length")
-
+
+ expect_equal(
+ usage_to_model_distribution(0, tut, dt, mean_retention = 5 * 365),
+ 0
+ )
+ expect_equal(
+ usage_to_model_distribution(1, tut, dt, mean_retention = 5 * 365),
+ 1
+ )
+ expect_equal(
+ usage_to_model_distribution(
+ c(1, 1),
+ (1:2) * 365,
+ (1:2) * 365,
+ mean_retention = 5 * 365
+ ),
+ c(1, 1)
+ )
+ expect_equal(
+ usage_to_model_distribution(
+ c(0, 0),
+ (1:2) * 365,
+ (1:2) * 365,
+ mean_retention = 5 * 365
+ ),
+ c(0, 0)
+ )
+ expect_equal(
+ usage_to_model_distribution(
+ c(1, 0),
+ (1:2) * 365,
+ (1:2) * 365,
+ mean_retention = 5 * 365
+ ),
+ c(1, 0)
+ )
+ expect_equal(
+ usage_to_model_distribution(
+ c(1, 1),
+ (1:2) * 365,
+ (1:3) * 365,
+ mean_retention = 5 * 365
+ ),
+ c(1, 1, NA)
+ )
+
+ expect_error(
+ usage_to_model_distribution(
+ tu,
+ tut,
+ dt,
+ distribution_lower = -1,
+ mean_retention = 5 * 365
+ ),
+ "All distribution lower values must be between 0 and 1"
+ )
+ expect_error(
+ usage_to_model_distribution(
+ tu,
+ tut,
+ dt,
+ distribution_lower = 6,
+ mean_retention = 5 * 365
+ ),
+ "All distribution lower values must be between 0 and 1"
+ )
+ expect_error(
+ usage_to_model_distribution(
+ tu,
+ tut,
+ dt,
+ distribution_upper = -1,
+ mean_retention = 5 * 365
+ ),
+ "All distribution upper values must be between 0 and 1"
+ )
+ expect_error(
+ usage_to_model_distribution(
+ tu,
+ tut,
+ dt,
+ distribution_upper = 6,
+ mean_retention = 5 * 365
+ ),
+ "All distribution upper values must be between 0 and 1"
+ )
+
+ expect_error(
+ usage_to_model_distribution(
+ tu,
+ tut,
+ dt,
+ distribution_lower = c(0.1, 0.1),
+ mean_retention = 5 * 365
+ ),
+ "distribution_timesteps, distribution_lower and distribution_upper must have equal lengths"
+ )
+ expect_error(
+ usage_to_model_distribution(
+ tu,
+ tut,
+ dt,
+ distribution_upper = c(0.1, 0.1),
+ mean_retention = 5 * 365
+ ),
+ "distribution_timesteps, distribution_lower and distribution_upper must have equal lengths"
+ )
+
+ expect_error(
+ usage_to_model_distribution(tu, c(tut, tut), dt, mean_retention = 5 * 365),
+ "Usage and usage timesteps must be the same length"
+ )
})
+test_that("malariasimulation usage fitting works - MAP model", {
+ tu <- 0
+ tut <- 365
+ dt <- 365
+
+ expect_equal(
+ usage_to_model_distribution(
+ 0,
+ tut,
+ dt,
+ net_loss_function = net_loss_map,
+ half_life = 2 * 365
+ ),
+ 0
+ )
+ expect_equal(
+ usage_to_model_distribution(
+ 1,
+ tut,
+ dt,
+ net_loss_function = net_loss_map,
+ half_life = 2 * 365
+ ),
+ 1
+ )
+ expect_equal(
+ usage_to_model_distribution(
+ c(1, 1),
+ (1:2) * 365,
+ (1:2) * 365,
+ net_loss_function = net_loss_map,
+ half_life = 2 * 365
+ ),
+ c(1, 1)
+ )
+ expect_equal(
+ usage_to_model_distribution(
+ c(0, 0),
+ (1:2) * 365,
+ (1:2) * 365,
+ net_loss_function = net_loss_map,
+ half_life = 2 * 365
+ ),
+ c(0, 0)
+ )
+ expect_equal(
+ usage_to_model_distribution(
+ c(1, 0),
+ (1:2) * 365,
+ (1:2) * 365,
+ net_loss_function = net_loss_map,
+ half_life = 2 * 365
+ ),
+ c(1, 0)
+ )
+ expect_equal(
+ usage_to_model_distribution(
+ c(1, 1),
+ (1:2) * 365,
+ (1:3) * 365,
+ net_loss_function = net_loss_map,
+ half_life = 2 * 365
+ ),
+ c(1, 1, NA)
+ )
+
+ expect_error(
+ usage_to_model_distribution(
+ tu,
+ tut,
+ dt,
+ distribution_lower = -1,
+ net_loss_function = net_loss_map,
+ half_life = 2 * 365
+ ),
+ "All distribution lower values must be between 0 and 1"
+ )
+ expect_error(
+ usage_to_model_distribution(
+ tu,
+ tut,
+ dt,
+ distribution_lower = 6,
+ net_loss_function = net_loss_map,
+ half_life = 2 * 365
+ ),
+ "All distribution lower values must be between 0 and 1"
+ )
+ expect_error(
+ usage_to_model_distribution(
+ tu,
+ tut,
+ dt,
+ distribution_upper = -1,
+ net_loss_function = net_loss_map,
+ half_life = 2 * 365
+ ),
+ "All distribution upper values must be between 0 and 1"
+ )
+ expect_error(
+ usage_to_model_distribution(
+ tu,
+ tut,
+ dt,
+ distribution_upper = 6,
+ net_loss_function = net_loss_map,
+ half_life = 2 * 365
+ ),
+ "All distribution upper values must be between 0 and 1"
+ )
+
+ expect_error(
+ usage_to_model_distribution(
+ tu,
+ tut,
+ dt,
+ distribution_lower = c(0.1, 0.1),
+ net_loss_function = net_loss_map,
+ half_life = 2 * 365
+ ),
+ "distribution_timesteps, distribution_lower and distribution_upper must have equal lengths"
+ )
+ expect_error(
+ usage_to_model_distribution(
+ tu,
+ tut,
+ dt,
+ distribution_upper = c(0.1, 0.1),
+ net_loss_function = net_loss_map,
+ half_life = 2 * 365
+ ),
+ "distribution_timesteps, distribution_lower and distribution_upper must have equal lengths"
+ )
+
+ expect_error(
+ usage_to_model_distribution(
+ tu,
+ c(tut, tut),
+ dt,
+ net_loss_function = net_loss_map,
+ half_life = 2 * 365
+ ),
+ "Usage and usage timesteps must be the same length"
+ )
+})
test_that("population_usage", {
-
timesteps <- 10 * 365
pu <- model_distribution_to_usage(
usage_timesteps = 1:timesteps,
@@ -40,10 +270,10 @@ test_that("population_usage", {
distribution_timesteps = 1,
mean_retention = 5 * 365
)
-
+
expect_equal(length(pu), timesteps)
expect_equal(pu, net_loss_exp(0:(timesteps - 1), 5 * 365))
-
+
dt <- c(1, 101, 201, 301)
pu <- model_distribution_to_usage(
usage_timesteps = 1:timesteps,
@@ -51,6 +281,30 @@ test_that("population_usage", {
distribution_timesteps = dt,
mean_retention = 5 * 365
)
-
+
expect_equal(pu[dt], rep(1, length(dt)))
-})
\ No newline at end of file
+})
+
+test_that("zero distributions are dealt with correctly", {
+ zero_dist <- model_distribution_to_usage(
+ usage_timesteps = 1:3,
+ distribution = c(0, 0),
+ distribution_timesteps = c(1, 2),
+ mean_retention = 5 * 365
+ )
+ expect_equal(zero_dist, c(0, 0, 0))
+})
+
+
+test_that("Input distribution estimation deals with
+ input timepoints after final target use timepoint elegantly", {
+ usage_to_model_distribution(
+ usage = 0.1,
+ usage_timesteps = 1,
+ distribution_timesteps = 1:3,
+ distribution_lower = rep(0, 3),
+ distribution_upper = rep(1, 3),
+ net_loss_function = net_loss_map,
+ half_life = 300
+ )
+})
diff --git a/vignettes/Metrics.Rmd b/vignettes/Metrics.Rmd
index 6165d9b..2e6ad0c 100644
--- a/vignettes/Metrics.Rmd
+++ b/vignettes/Metrics.Rmd
@@ -168,7 +168,7 @@ to a smooth-compact function (net_loss_function = net_loss_map). This in line
with the paper by Bertozzi-Villa et al.
An alternative option is to assume exponential net loss (`net_loss_function = net_loss_exp`),
-which corresponds to the assumption in malariasimulation.
+which corresponds to the default assumption in malariasimulation.
The proportion of nets retained over time are visualised for both options below,
for a 3 year distribution cycle and a net half life of 1.64 years.
diff --git a/vignettes/malariasimulation.Rmd b/vignettes/malariasimulation.Rmd
index 7b93050..b84e959 100644
--- a/vignettes/malariasimulation.Rmd
+++ b/vignettes/malariasimulation.Rmd
@@ -73,7 +73,7 @@ simparams <- get_parameters(
coverages = data$model_input,
retention = 700,
dn0 = matrix(rep(0.533, 10), nrow = 10, ncol = 1),
- rn = matrix(rep(0.56, 10), nrow = 10, ncol = 1),
+ rn = matrix(rep(0.36, 10), nrow = 10, ncol = 1),
rnm = matrix(rep(0.24, 10), nrow = 10, ncol = 1),
gamman = rep(2.64 * 365, 10)
)