George G. Vega Yon, Ph.D. 2025-10-23
Caution
This project is a work in progress. Use it at your own risk. This model simulates a single school, so community transmission is not included.
Important
The model makes several assumptions that may not hold in real-world scenarios. One important assumption is that interactions between agents are based solely on class assignments, and not based on friendship networks or other social structures. This assumption reflects strongly in the effect of mid-risk quarantine (see below for more details).
We are using the ModelMeaslesMixingRiskQuarantine() model from the
epiworldR package (version 0.10.0.0 or higher). This model uses a
mixing matrix to represent how agents’ interactions are distributed. In
this case, groups represent classrooms in a school, so kids will have
more interactions with kids in their own class than with kids from other
classes.
The model contains the full disease progression for measles, including
the incubation period, prodromal phase, and rash phase. The model
assumes that kids in the rash phase are isolated from their peers.
Nonetheless, the model is calibrated to reflect the measles
The quarantine process is triggered when an agent is detected during the rash period. This could occur for more than one agent in the same step. Quarantine process only applies to unvaccinated agents, and the duration of quarantine depends on the risk level of the agent, as defined below.
This document illustrates an experiment using the epiworldR package to
simulate measles transmission under a tiered quarantine strategy. In the
tier quarantine system, agents have different quarantine durations as a
function of their risk level, which are defined as follows:
- High risk: Agents in the same classroom as an infected individual.
- Medium risk: Agents who were not in the same classroom as the infected individual, but were in direct contact with them.
- Low risk: Agents who were not in the same classroom or direct contact with the infected individual.
Quarantine only applies to unvaccinated agents. The simulation settings are as follows:
- Individual school with 600 students distributed across 20 classes (30 students per class).
- The contact rate is given by our previous estimates for within-class and between-class interactions: 83% of contacts occur within the same class, while 17% occur between different classes.
- The basic reproduction number (R0) is set to 15, reflecting the high transmissibility of measles.
- Contact tracing is assumed to be 100% effective, as agents’ willingness to isolate and quarantine.
The following code block sets up some of the simulation parameters,
including sourcing the simulator function in the file
simulator.R:
library(epiworldR)Thank you for using epiworldR! Please consider citing it in your work.
You can find the citation information by running
citation("epiworldR")
library(data.table)
library(ggplot2)
source("simulator.R")
# Simulation parameters
n_sims <- 2000
n_agents <- 600
n_classes <- 20
n_agents_per_class <- n_agents / n_classes
n_days <- 100
n_threads <- 10
# Makesure it's even
stopifnot(n_agents_per_class %% 1 == 0)The particular disease parameters for measles, including the mixing matrix that will be used for the simulation, are defined as follows:
# Disease parameters
R0 <- 15
contact_rate <- 20
incubation <- 12
prodromal <- 4
rash <- 3
# Creating the mixing matrix
within_class_contact_rate <- 0.83
between_class_contact_rate <- 1 - within_class_contact_rate
contact_matrix <- matrix(
between_class_contact_rate / (n_classes - 1),
nrow = n_classes,
ncol = n_classes
)
diag(contact_matrix) <- within_class_contact_rate
# Calibrating infection probability
p_infect <- R0 / (contact_rate) * (1/prodromal)We will test the model using the following scenarios:
- 50%, 80%, and 95% vaccination coverage.
- Quarantine days set to 0, 7, 14, and 21 days.
To assess the risk effect between different quarantine strategies, we report the probability of observing outbreaks of various sizes rather than means and medians. Specifically, we calculate:
- P(≥10): Probability that an outbreak reaches 10 or more infected individuals
- P(≥20): Probability that an outbreak reaches 20 or more infected individuals
- P(≥50): Probability that an outbreak reaches 50 or more infected individuals
This approach provides a clearer picture of the distribution’s tail behavior and allows for better comparison of risk across different strategies.
ans_none <- simulator(duration = c(0L, 0L, 0L), vaccinated = 0.0)
ans_only_high <- simulator(duration = c(21L, 0L, 0L), vaccinated = 0.0)
ans_only_medium <- simulator(duration = c(0L, 21L, 0L), vaccinated = 0.0)
ans_only_low <- simulator(duration = c(0L, 0L, 21L), vaccinated = 0.0)
# Tabulating the results
tabulator(
list(
"No Quarantine" = ans_none,
"Only High Risk Quarantine" = ans_only_high,
"Only Medium Risk Quarantine" = ans_only_medium,
"Only Low Risk Quarantine" = ans_only_low
)
)| Scenario | P(≥10) | P(≥20) | P(≥50) |
|---|---|---|---|
| No Quarantine | 0.991 | 0.991 | 0.991 |
| Only High Risk Quarantine | 0.928 | 0.919 | 0.910 |
| Only Medium Risk Quarantine | 0.987 | 0.987 | 0.987 |
| Only Low Risk Quarantine | 0.977 | 0.960 | 0.632 |
Probability of outbreak sizes across different quarantine scenarios.
For this scenario, we simulate with 50% vaccination coverage and compare the following tiered quarantine strategies:
- Baseline: 21 days for all risk levels.
- Strategy 1: 21 days for high risk, 14 days for medium and low risk.
- Strategy 2: 21 days for high risk, 7 days for medium and low risk.
- Strategy 3: 21 days for high risk, no quarantine for medium and low risk.
ans_50_baseline <- simulator(duration = c(21L, 21L, 21L), vaccinated = 0.5)
ans_50_strategy1 <- simulator(duration = c(21L, 14L, 14L), vaccinated = 0.5)
ans_50_strategy2 <- simulator(duration = c(21L, 7L, 7L), vaccinated = 0.5)
ans_50_strategy3 <- simulator(duration = c(21L, 0L, 0L), vaccinated = 0.5)
# Tabulating the results
tabulator(
list(
"Baseline (21,21,21)" = ans_50_baseline,
"Strategy 1 (21,14,14)" = ans_50_strategy1,
"Strategy 2 (21,7,7)" = ans_50_strategy2,
"Strategy 3 (21,0,0)" = ans_50_strategy3
)
)| Scenario | P(≥10) | P(≥20) | P(≥50) |
|---|---|---|---|
| Baseline (21,21,21) | 0.686 | 0.513 | 0.313 |
| Strategy 1 (21,14,14) | 0.705 | 0.506 | 0.311 |
| Strategy 2 (21,7,7) | 0.746 | 0.633 | 0.425 |
| Strategy 3 (21,0,0) | 0.800 | 0.751 | 0.674 |
Probability of outbreak sizes across different quarantine scenarios.
Similar to the previous scenario, we simulate with 80% vaccination coverage and compare the same tiered quarantine strategies:
ans_80_baseline <- simulator(duration = c(21L, 21L, 21L), vaccinated = 0.8)
ans_80_strategy1 <- simulator(duration = c(21L, 14L, 14L), vaccinated = 0.8)
ans_80_strategy2 <- simulator(duration = c(21L, 7L, 7L), vaccinated = 0.8)
ans_80_strategy3 <- simulator(duration = c(21L, 0L, 0L), vaccinated = 0.8)
# Tabulating the results
tabulator(
list(
"Baseline (21,21,21)" = ans_80_baseline,
"Strategy 1 (21,14,14)" = ans_80_strategy1,
"Strategy 2 (21,7,7)" = ans_80_strategy2,
"Strategy 3 (21,0,0)" = ans_80_strategy3
)
)| Scenario | P(≥10) | P(≥20) | P(≥50) |
|---|---|---|---|
| Baseline (21,21,21) | 0.239 | 0.106 | 0.092 |
| Strategy 1 (21,14,14) | 0.258 | 0.103 | 0.081 |
| Strategy 2 (21,7,7) | 0.308 | 0.142 | 0.089 |
| Strategy 3 (21,0,0) | 0.385 | 0.228 | 0.054 |
Probability of outbreak sizes across different quarantine scenarios.
Finally, we simulate with 90% vaccination coverage and compare the same tiered quarantine strategies:
ans_90_baseline <- simulator(duration = c(21L, 21L, 21L), vaccinated = 0.9)
ans_90_strategy1 <- simulator(duration = c(21L, 14L, 14L), vaccinated = 0.9)
ans_90_strategy2 <- simulator(duration = c(21L, 7L, 7L), vaccinated = 0.9)
ans_90_strategy3 <- simulator(duration = c(21L, 0L, 0L), vaccinated = 0.9)
# Tabulating the results
tabulator(
list(
"Baseline (21,21,21)" = ans_90_baseline,
"Strategy 1 (21,14,14)" = ans_90_strategy1,
"Strategy 2 (21,7,7)" = ans_90_strategy2,
"Strategy 3 (21,0,0)" = ans_90_strategy3
)
)| Scenario | P(≥10) | P(≥20) | P(≥50) |
|---|---|---|---|
| Baseline (21,21,21) | 0.051 | 0.032 | 0.032 |
| Strategy 1 (21,14,14) | 0.059 | 0.026 | 0.026 |
| Strategy 2 (21,7,7) | 0.067 | 0.023 | 0.021 |
| Strategy 3 (21,0,0) | 0.089 | 0.018 | 0.008 |
Probability of outbreak sizes across different quarantine scenarios.
For this scenario, we simulate with 80% vaccination coverage and a maximum quarantine duration of 14 days, comparing the same tiered quarantine strategies:
ans_80_21_baseline <- simulator(duration = c(21L, 21L, 21L), vaccinated = 0.8)
ans_80_14_strategy1 <- simulator(duration = c(14L, 14L, 14L), vaccinated = 0.8)
ans_80_14_strategy2 <- simulator(duration = c(14L, 10L, 10L), vaccinated = 0.8)
ans_80_14_strategy3 <- simulator(duration = c(14L, 7L, 7L), vaccinated = 0.8)
ans_80_14_strategy4 <- simulator(duration = c(14L, 0L, 0L), vaccinated = 0.8)
# Tabulating the results
tabulator(
list(
"Baseline (21,21,21)" = ans_80_21_baseline,
"Strategy 1 (14,14,14)" = ans_80_14_strategy1,
"Strategy 2 (14,10,10)" = ans_80_14_strategy2,
"Strategy 3 (14,7,7)" = ans_80_14_strategy3,
"Strategy 4 (14,0,0)" = ans_80_14_strategy4
)
)| Scenario | P(≥10) | P(≥20) | P(≥50) |
|---|---|---|---|
| Baseline (21,21,21) | 0.239 | 0.106 | 0.092 |
| Strategy 1 (14,14,14) | 0.304 | 0.137 | 0.108 |
| Strategy 2 (14,10,10) | 0.336 | 0.146 | 0.100 |
| Strategy 3 (14,7,7) | 0.360 | 0.177 | 0.108 |
| Strategy 4 (14,0,0) | 0.449 | 0.290 | 0.079 |
Probability of outbreak sizes across different quarantine scenarios.
Combining some of the results from different scenarios for a final comparison of the tiered quarantine strategies with 80% vaccination coverage:
tabulator(
list(
"Baseline (21,21,21)" = ans_80_21_baseline,
"Strategy 1 (14,14,14)" = ans_80_14_strategy1,
"Strategy 2 (14,10,10)" = ans_80_14_strategy2,
"Strategy 3 (14,7,7)" = ans_80_14_strategy3
)
)| Scenario | P(≥10) | P(≥20) | P(≥50) |
|---|---|---|---|
| Baseline (21,21,21) | 0.239 | 0.106 | 0.092 |
| Strategy 1 (14,14,14) | 0.304 | 0.137 | 0.108 |
| Strategy 2 (14,10,10) | 0.336 | 0.146 | 0.100 |
| Strategy 3 (14,7,7) | 0.360 | 0.177 | 0.108 |
Probability of outbreak sizes across different quarantine scenarios.
The probability-based metrics provide a clearer picture of outbreak risk across different strategies. By examining the probability of reaching specific outbreak thresholds (10, 20, and 50 infected individuals), we can better assess the practical implications of each quarantine strategy. The distribution of total infected individuals can be further explored through density plots:
# We can group the four into a single plot (histogram)
# for visual comparison
combined_results <- rbind(
data.table(Scenario = "Baseline (21,21,21)", ans_80_21_baseline),
data.table(Scenario = "Strategy 1 (14,14,14)", ans_80_14_strategy1),
data.table(Scenario = "Strategy 2 (14,10,10)", ans_80_14_strategy2),
data.table(Scenario = "Strategy 3 (14,7,7)", ans_80_14_strategy3)
)
combined_results[total_infected < 50] |>
ggplot(aes(x = total_infected, color = Scenario)) +
geom_density(linewidth=1.5) +
labs(
title = "Distribution of Total Infected Individuals - Final Comparison",
x = "Total Infected Individuals",
y = "Frequency"
) +
theme_minimal()Looking at the density plot, we can see that the ordering of the distribution in outbreak sizes is consistent with the expected impact of the different quarantine strategies.
The model presented here is a simplification of reality trying to explore what a change in the quarantine strategy could mean for measles outbreaks in school settings. The results suggest that quarantine duration may be reduced without significantly increasing outbreak sizes in the context of a relatively high vaccination coverage (80% or higher). However, it is important to note that the model assumes perfect compliance with quarantine measures and does not account for community transmission outside the school setting.
The mid-risk quarantine strategy–which applies to agents who are not in the same classroom but were in direct contact with an infected individual–shows a marginal effect on outbreak sizes. Nonetheless, this finding is contingent on the assumption that interactions happen randomly based on class assignments, so, in real-world scenarios where social networks and friendships play a significant role, the impact of mid-risk quarantine could be more pronounced. Because of this, it would be prudent to include mid-risk quarantine in the same category as high-risk quarantine until more detailed models are developed.
This analysis was performed using epiworldR version 0.10.0.0, with R
version R version 4.5.1 (2025-06-13). You can get the latest version of
epiworldR from GitHub at https://github.com/UofUEpiBio/epiworldR.
