Switch to unified view

a b/tests/testthat/test_outbreaker.R
1
context("Test outbreaker")
2
current_R_version <- gsub("R version ([0-9.]+) .+$", "\\1", R.version.string)
3
4
## test output format ##
5
test_that("outbreaker's output have expected format", {
6
    ## skip on CRAN
7
    skip_on_cran()
8
9
10
    ## get data
11
    data(fake_outbreak)
12
    x <- fake_outbreak
13
14
    ## run outbreaker
15
    data <- list(dna = x$dna, dates = x$onset, w_dens = x$w)
16
    config <- list(n_iter = 10, sample_every = 1, find_import = FALSE)
17
    out <- outbreaker(data, config)
18
19
20
    out_df <- as.data.frame(out)
21
22
    data <- list(dates = x$onset, w_dens = x$w)
23
    out2 <- outbreaker(data, config)
24
25
    ## check output
26
    expect_is(out, "outbreaker_chains")
27
    expect_is(out_df, "data.frame")
28
    expect_equal(nrow(out), 10)
29
    expect_true(!any(is.na(out_df$post)))
30
    expect_true(all(out_df$post> -1e30))
31
32
})
33
34
35
36
37
## test convergence in various settings ##
38
test_that("results ok: DNA + time", {
39
    ## skip on CRAN
40
    skip_on_cran()
41
42
43
    ## get data
44
    data(fake_outbreak)
45
    x <- fake_outbreak
46
47
    ## outbreaker DNA + time ##
48
    ## analysis
49
    set.seed(1)
50
    data <- list(dna = x$dna, dates = x$onset, w_dens = x$w)
51
    config <- list(n_iter = 5000, sample_every = 50,
52
                   init_tree = "seqTrack", find_import = TRUE,
53
                   move_pi = FALSE)
54
55
    out <- outbreaker(data = data, config = config)
56
57
    ## checks
58
    out_smry <- summary(out, burnin = 1000)
59
60
    ## approx log post values
61
    expect_true(min(out_smry$post) > -1250)
62
63
    ## at least 80% ancestries correct
64
    temp <- mean(out_smry$tree$from==x$ances, na.rm = TRUE)
65
    expect_true(temp > .8)
66
67
    ## infection date within 3 days on average
68
    temp <- mean(abs(out_smry$tree$time - x$onset), na.rm = TRUE)
69
    expect_true(temp < 3.5)
70
71
    ## mu within reasonable ranges
72
    expect_true(out_smry$mu[2] > 1e-5 &&
73
                out_smry$mu[5] < 2e-4)
74
75
})
76
77
78
79
80
81
test_that("results ok: time, no DNA", {
82
    ## skip on CRAN
83
    skip_on_cran()
84
85
86
    ## get data
87
    data(fake_outbreak)
88
    x <- fake_outbreak
89
90
    ## outbreaker time, no DNA ##
91
    ## analysis
92
    set.seed(1)
93
94
    data <- list(dates = x$onset, w_dens = x$w)
95
    config <- list(n_iter = 5000, sample_every = 50,
96
                   init_tree="star", find_import = FALSE,
97
                   move_kappa = FALSE)
98
99
    out_no_dna <- outbreaker(data = data, config = config)
100
101
    ## checks
102
    out_no_dna.smry <- summary(out_no_dna, burnin = 1000)
103
104
    ## approx log post values
105
    expect_true(min(out_no_dna.smry$post) > -90)
106
107
    ## infection date within 3 days on average
108
    temp <- mean(abs(out_no_dna.smry$tree$time - x$onset), na.rm = TRUE)
109
    expect_true(temp < 3.5)
110
111
    ## check that support for ancestries is weak
112
    sup <- na.omit(out_no_dna.smry$tree$support)
113
    expect_lt(quantile(sup, .9), .55)
114
    expect_lt(mean(sup), .35)
115
116
})
117
118
119
120
test_that("results ok: time, ctd, DNA", {
121
    ## skip on CRAN
122
    skip_on_cran()
123
124
125
    ## get data
126
    data(fake_outbreak)
127
    x <- fake_outbreak
128
129
    ## outbreaker time, ctd, no DNA ##
130
    ## analysis
131
    ## set the random number generator kind to old R
132
    suppressWarnings(RNGversion("3.5.2"))
133
    set.seed(1)
134
135
    tTree <- data.frame(i = x$ances,
136
                        j = 1:length(x$ances))
137
138
    ctd <- sim_ctd(tTree, eps = 0.9, lambda = 0.1)
139
140
    data <- list(dates = x$onset, w_dens = x$w,
141
                 ctd = ctd[,1:2], dna = x$dna)
142
    config <- list(n_iter = 5000, sample_every = 50,
143
                   init_tree="star", find_import = FALSE,
144
                   move_kappa = FALSE)
145
146
    out_ctd <- outbreaker(data = data, config = config)
147
148
    ## checks
149
    out_ctd.smry <- summary(out_ctd, burnin = 1000)
150
151
    ## at least 90% ancestries correct
152
    temp <- mean(out_ctd.smry$tree$from==x$ances, na.rm = TRUE)
153
    expect_true(temp > .9)
154
155
    ## eps and lambda parameter estimates within reasonable ranges
156
    quant_eps <- quantile(out_ctd$eps, c(0.25, 0.75))
157
    expect_true(quant_eps[[1]] > 0.7 &
158
                quant_eps[[2]] < 0.95)
159
160
    quant_lambda <- quantile(out_ctd$lambda, c(0.25, 0.75))
161
    expect_true(quant_lambda[[1]] > 0.05 &
162
                quant_lambda[[2]] < 0.35)
163
164
    ## approx log post values
165
    expect_true(min(out_ctd.smry$post) > -1200)
166
167
    ## reset the Random number generator kind
168
    RNGversion(current_R_version)
169
170
})
171
172
173
174
175
test_that("results ok: easy run, no missing cases, no import", {
176
    ## skip on CRAN
177
    skip_on_cran()
178
179
180
    ## get data
181
    data(fake_outbreak)
182
    x <- fake_outbreak
183
184
    ## outbreaker, no missing cases ##
185
    ## analysis
186
    set.seed(1)
187
    config <-  list(n_iter = 5e3, sample_every = 50,
188
                    init_tree = "seqTrack", move_kappa = FALSE,
189
                    move_pi = FALSE, init_pi = 1,
190
                    find_import = FALSE)
191
    data <- list(dna = x$dna, dates = x$onset, w_dens = x$w)
192
193
    out_no_missing <- outbreaker(data = data, config = config)
194
195
    ## checks
196
    out_no_missing_smry <- summary(out_no_missing, burnin = 3500)
197
198
    ## approx log post values
199
    expect_true(min(out_no_missing_smry$post) > -935)
200
201
    ## at least 85% ancestries correct
202
    temp <- mean(out_no_missing_smry$tree$from==x$ances, na.rm = TRUE)
203
    expect_true(temp > .85)
204
205
    ## infection datewithin 3 days on average
206
    temp <- mean(abs(out_no_missing_smry$tree$time - x$onset), na.rm = TRUE)
207
    expect_true(temp < 3.5)
208
209
})
210
211
212
213
test_that("results ok: no missing cases, detect imported cases",
214
{
215
    ## skip on CRAN
216
    skip_on_cran()
217
218
219
    ## get data
220
    data(fake_outbreak)
221
    x <- fake_outbreak
222
223
    ## outbreaker, no missing cases, detect imported cases ##
224
    ## analysis
225
    set.seed(1)
226
    out_with_import <- outbreaker(data = list(dna = x$dna, dates = x$onset,
227
                                              w_dens = x$w),
228
                                  config = list(n_iter = 5000, sample_every = 100,
229
                                                init_tree="star",
230
                                                move_kappa = FALSE, move_pi = FALSE,
231
                                                init_pi = 1, find_import = TRUE)
232
                                  )
233
234
    ## checks
235
    out_with_import_smry <- summary(out_with_import, burnin = 500)
236
    out_with_import_smry$tree$from[is.na(out_with_import_smry$tree$from)] <- 0
237
    x$ances[is.na(x$ances)] <- 0
238
239
    ## approx log post values
240
    expect_true(min(out_with_import_smry$post) > -460)
241
242
    ## at least 80% ancestries correct
243
    temp <- mean(out_with_import_smry$tree$from==x$ances, na.rm = TRUE)
244
    expect_true(temp >= .80)
245
246
    ## infection datewithin 3 days on average
247
    temp <- mean(abs(out_with_import_smry$tree$time - x$onset), na.rm = TRUE)
248
    expect_true(temp < 3.5)
249
250
})
251
252
253
254
255
256
257
test_that("results ok: kappa and pi", {
258
    ## skip on CRAN
259
    skip_on_cran()
260
261
262
    ## get data
263
    onset <- c(0, 2, 6, 13)
264
    w <- c(.25, .5, .25)
265
266
    ## outbreaker, no missing cases, detect imported cases ##
267
    ## analysis
268
    set.seed(1)
269
270
    data <- list(dates = onset, w_dens = w)
271
    config <- list(n_iter = 5000, sample_every = 50, init_tree = "star",
272
                   move_kappa = TRUE, move_pi = TRUE, init_pi = 1,
273
                   find_import = FALSE, max_kappa = 10)
274
275
276
    out <- outbreaker(data, config)
277
278
    smry <- summary(out, burnin = 500)
279
280
    ## checks
281
    expect_equal(smry$tree$from, c(NA, 1, 2, 3))
282
    expect_equal(smry$tree$generations, c(NA, 1, 2, 4))
283
    expect_true(min(smry$post) > -35)
284
    expect_true(all(smry$pi[3:4] > 0.5 & smry$pi[3:4] < 0.8))
285
286
})
287
288
289
290
291
292
293
test_that("results ok: kappa from genetic data", {
294
295
    ## skip on CRAN
296
    skip_on_cran()
297
298
    dates <- c(0, 5, 15, 20, 30)
299
    w <- dnorm(1:10, 5, 1)
300
    dna <- matrix(c("A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
301
                    "T", "T", "A", "A", "A", "A", "A", "A", "A", "A", "A", "A",
302
                    "T", "T", "G", "G", "G", "G", "A", "A", "A", "A", "A", "A",
303
                    "T", "T", "G", "G", "G", "G", "T", "T", "A", "A", "A", "A",
304
                    "T", "T", "G", "G", "G", "G", "T", "T", "G", "G", "G", "G"),
305
                  byrow = TRUE, nrow = 5)
306
    dna <- ape::as.DNAbin(dna)
307
    data <- outbreaker_data(dates = dates, dna = dna, w_dens = w)
308
    config <- create_config(init_mu = 2/12, move_mu = FALSE)
309
    res <- outbreaker(data, config)
310
    expect_equal(summary(res)$tree$generations,
311
                 c(NA, 1L, 2L, 1L, 2L))
312
313
})
314
315
316
317
318
319
320
321
322
323
test_that("results ok: outbreaker with custom priors",
324
{
325
    ## skip on CRAN
326
    skip_on_cran()
327
328
329
    ## get data
330
    data(fake_outbreak)
331
    x <- fake_outbreak
332
333
    data <- list(dna = x$dna, dates = x$onset, w_dens = x$w)
334
335
    config <-  list(n_iter = 5e3, sample_every = 50,
336
                    init_tree = "star", move_kappa = TRUE,
337
                    move_pi = TRUE, init_pi = 0.9,
338
                    find_import = FALSE)
339
340
341
    ## plot(function(x) dbeta(x, 50, 25)) # to see the distribution
342
343
    f_pi_1 <- function(x) dbeta(x$pi, 100, 1, log = TRUE) # stronger prior
344
    f_pi_2 <- function(x) 0.0 # flat prior
345
346
    set.seed(1)
347
348
    out_1 <- outbreaker(data, config, priors = list(pi = f_pi_1))
349
    out_2 <- outbreaker(data, config, priors = list(pi = f_pi_2))
350
351
    smry_1 <- summary(out_1, burnin = 500)
352
    smry_2 <- summary(out_2, burnin = 500)
353
354
    expect_true(smry_1$pi[2] > 0.9)
355
    expect_true(smry_2$pi[2] > 0.6 && smry_2$pi[5] < 0.9)
356
357
})
358
359
360
361
362
363
364
365
366
test_that("results ok: outbreaker with fixed number returning priors and likelihoods",
367
{
368
    ## skip on CRAN
369
    skip_on_cran()
370
371
372
    ## get data
373
374
    data(fake_outbreak)
375
    x <- fake_outbreak
376
377
    data <- list(dna = x$dna, dates = x$onset, w_dens = x$w)
378
379
    config <-  list(n_iter = 1000, sample_every = 10,
380
                    init_tree = "star", move_kappa = TRUE,
381
                    move_pi = TRUE, init_pi = 1,
382
                    find_import = FALSE)
383
384
385
    ## custom functions
386
387
    f1 <- function(x) return(0.0)
388
    f2 <- function(x, y) return(0.0)
389
    f3 <- function(x) return(1.123)
390
391
    priors1 <- custom_priors(mu = f1, pi = f1)
392
    priors2 <- custom_priors(mu = f1, pi = f3)
393
394
    ll <- custom_likelihoods(genetic = f2,
395
                             timing_infections = f2,
396
                             timing_sampling = f2,
397
                             reporting = f2)
398
399
400
    ## tests
401
    out1 <- outbreaker(data, config, priors1, ll)
402
    out2 <- outbreaker(data, config, priors2, ll)
403
404
    expect_true(all(out1$post == 0))
405
    expect_true(all(out2$post == 1.123))
406
407
})
408
409
410
411
412
413
## test consensus tree
414
test_that("test consensus trees", {
415
416
    ## skip on CRAN
417
    skip_on_cran()
418
419
420
    ## get data
421
    data(fake_outbreak)
422
    x <- fake_outbreak
423
424
    ## outbreaker DNA + time ##
425
    ## analysis
426
    set.seed(1)
427
    data <- list(dna = x$dna, dates = x$onset, w_dens = x$w)
428
    config <- list(n_iter = 5000, sample_every = 50,
429
                   init_tree = "seqTrack", find_import = TRUE,
430
                   move_pi = FALSE)
431
432
    out <- outbreaker(data = data, config = config)
433
434
    ## checks
435
    out_smry_mpa <- summary(out, burnin = 1000, method = 'mpa')
436
    out_smry_dec <- summary(out, burnin = 1000, method = 'decycle')
437
438
    ## as there are no cycles, these should be the same
439
    testthat::expect_equal(out_smry_mpa$tree$from,
440
                           out_smry_dec$tree$from)
441
442
})