Testing frequency to ensure workplace safety

Background

In a population where there is constant threat of community infection, there is a need to test everyone to ensure workplace safety.

The goal of this simulation is to determine how many in the cohort would be infected with periodic testing with specified intervals.

Assumptions

  1. Risk of community spread is 20/10,000 to 50/10,000 per day, default to 0.0022.
  2. Cohort of size 10 to 40, with no virus at the beginning.
  3. Test everyone in the cohor either every week, every 3 days or every 2 weeks.

Simulations

The simulation could be performed with the following command

outbreak_simulator --rep 10000 --popsize {ps} --handle-symptomatic remove --stop-if 't>90' --logfile p{ps}_t{ti}.log \
        --plugin community_infection --probability 0.005 --interval 1  \
        --plugin testing --interval {ti} --proportion 1 --handle-positive remove \
        --plugin stat --at 14 90

where

  • Simulation will last 90 days.
  • Plugin community_infection infects everyone at a given probability at given interval
  • Plugin testing tests everyone (proportion=1) and remove infected individuals.
  • Plugin stat to output population statistics.

Here we use sos workflow to execute simulations for population size (ps) 10, 20, 30, 40, and testing frequency (ti) 0 (no test at all), 3 (every 3 days), 7, and 14.

input: for_each=[dict(ps=[10, 20, 30, 40]), dict(ti=[0, 3, 7, 14])]

task: queue='localhost'
sh: expand=True, template_name='conda', env_name='ictr'
    outbreak_simulator --rep 10000 --popsize {ps} --handle-symptomatic remove --stop-if 't>90' --logfile p{ps}_t{ti}.log \
        --plugin community_infection --probability 0.0022 --interval 1  \
        --plugin testing --interval {ti} --proportion 1 --handle-positive remove \
        --plugin stat --at 14 90

Results

The log file of the simulations contains event STAT with population size and INFECTION for infections, and the by parameter can be used to differentiate infection within the cohort (by a certain ID) or from community.

The following table shows

  1. Average number of uninfected: Mean remaining population size after 90 days.
  2. Std of uninfected: Standard deviation of remaining population size.
  3. proportion of none infected: Proportion of simulations with no infection at the end.
  4. Average number of community infection: Average number of community infections detected.
  5. Average number of within-cohort infection: Average number of within cohort infection.
%preview summary.csv

import pandas as pd

def param(data, name):
    stat = data[(data['event'] == 'STAT') & (data['time'] == 90)]
    return stat.apply(lambda x: int(x['params'].split(name+'=')[1].split(',')[0]), axis=1)

def infect(data):
    infect = data[data['event'] == 'INFECTION']
    by = infect.apply(lambda x: 'by' in x['params'], axis=1)
    return infect.shape[0] - sum(by), sum(by)

with open('summary.csv', 'w') as sc:
    sc.write(','.join([
        'Cohort size',
        'Community infection rate',
        'Test frequency (0 for no test)',
        'Average number of uninfected',
        'Std of uninfected',
        'Proportion of none infected',
        'Average number of community infection',
        'Average number of within-cohort infection']) + '\n')
    for ps in [10, 20, 30, 40]:
        for ti in [0, 3, 7, 14]:
            data = pd.read_csv(f'p{ps}_t{ti}.log', sep='\t')
            es = param(data, 'n_popsize') - param(data, 'n_infected')
            pna = 100 * sum(es == ps) / 10000
            community_infect, within_infect = infect(data)
            sc.write(f'{ps}, {0.0022}, {ti}, {es.mean():.1f}, {es.std():.1f}, {pna:.2f}%, {community_infect/10000:.1f}, {within_infect/10000:.1f}\n')

Cohort size Community infection rate Test frequency (0 for no test) Average number of uninfected Std of uninfected Proportion of none infected Average number of community infection Average number of within-cohort infection
10 0.0022 0 3.7 2.6 1.01% 2.9 3.5
10 0.0022 3 5.9 1.8 1.14% 3.6 0.5
10 0.0022 7 5.2 2.1 1.14% 3.4 1.5
10 0.0022 14 4.5 2.4 1.15% 3.1 2.4
20 0.0022 0 6.2 3.9 0.00% 5.3 8.5
20 0.0022 3 11.8 2.5 0.02% 7.1 1.2
20 0.0022 7 10.1 3.2 0.03% 6.6 3.3
20 0.0022 14 8.3 3.7 0.00% 6.1 5.6
30 0.0022 0 8.5 5.0 0.00% 7.7 13.8
30 0.0022 3 17.6 3.1 0.00% 10.6 1.9
30 0.0022 7 15.0 3.9 0.00% 9.9 5.2
30 0.0022 14 12.0 4.8 0.00% 9.0 9.0
40 0.0022 0 10.8 5.9 0.00% 10.0 19.3
40 0.0022 3 23.4 3.6 0.00% 14.2 2.5
40 0.0022 7 19.9 4.6 0.00% 13.2 7.0
40 0.0022 14 15.9 5.6 0.00% 11.9 12.3

Not surprisingly, the results show that

  1. Risk of infection increases with larger cohort size
  2. More frequent tests will reduce the number of within-cohort infection

Availability

This notebook is available under the Applications directory of the GitHub repository of the COVID19 Outbreak Simulator. It can be executed with sos-papermill with the following parameters, or using a docker image bcmictr/outbreak-simulator-notebook as described in here.