context("test_threads(.dry_run=T)")
###################################
# testing single model submission
###################################
# define constants
MODEL_DIR_BBI <- file.path(dirname(ABS_MODEL_DIR), "test-test-threads-models")
CTL_TEST_COMPLEX_FILE <- file.path(MODEL_DIR_X, "acop-fake-bayes.ctl")
CTL_TEST_COMPLEX_FILE2 <- file.path(MODEL_DIR_X, "example2_saemimp.ctl")
CTL_TEST_COMPLEX_FILE3 <- file.path(MODEL_DIR_X, "iovmm.mod")
CTL_TEST_COMPLEX_FILE4 <- file.path(MODEL_DIR_X, "acop-onlysim.ctl")
# cleanup function
cleanup_bbi <- function(.recreate_dir = FALSE) {
if (fs::dir_exists(MODEL_DIR_BBI)) fs::dir_delete(MODEL_DIR_BBI)
if (isTRUE(.recreate_dir)) fs::dir_create(MODEL_DIR_BBI)
}
cleanup_bbi(.recreate_dir = TRUE)
get_est_options <- function(mods, search_opts = c("maxeval", "niter", "nburn")){
mod_names <- purrr::map_chr(mods, ~ basename(.x$absolute_model_path))
est_opts <- map(mods, function(.mod){
mod_path <- get_model_path(.mod)
mod_lines <- mod_path %>% readLines()
ctl <- nmrec::parse_ctl(mod_lines)
ests <- nmrec::select_records(ctl, "est")
rec_names <- paste0("est_rec_", seq_along(ests))
mod_est_opts <- purrr::map(ests, function(est_i){
opts <- purrr::map(search_opts, ~{
opt <- nmrec::get_record_option(est_i, .x)
if(!is.null(opt)){
val <- as.numeric(opt$value)
names(val) <- opt$name_raw
val
} else{
NULL
}
}) %>% purrr::flatten_dbl()
if(!rlang::is_empty(opts)) opts else NULL
})
mod_est_opts %>% stats::setNames(rec_names) %>% purrr::compact()
})
est_opts %>% stats::setNames(mod_names)
}
withr::with_options(list(bbr.bbi_exe_path = read_bbi_path()), {
# cleanup when done
on.exit({
Sys.sleep(3) # wait for some NONMEM mess to delete itself
cleanup_bbi()
})
if (fs::file_exists(file.path(MODEL_DIR_BBI, "bbi.yaml"))) fs::file_delete(file.path(MODEL_DIR_BBI, "bbi.yaml"))
# create fake bbi.yaml
readr::write_file("created_by: test-test-threads", file.path(MODEL_DIR_BBI, "bbi.yaml"))
# copy model files into new model dir
fs::file_copy(CTL_TEST_FILE, MODEL_DIR_BBI)
fs::file_copy(CTL_TEST_COMPLEX_FILE, MODEL_DIR_BBI)
fs::file_copy(CTL_TEST_COMPLEX_FILE2, MODEL_DIR_BBI)
fs::file_copy(CTL_TEST_COMPLEX_FILE3, MODEL_DIR_BBI)
fs::file_copy(CTL_TEST_COMPLEX_FILE4, MODEL_DIR_BBI)
mod1 <- new_model(
file.path(MODEL_DIR_BBI, "1"),
.description = "original test-test-threads model",
.tags = ORIG_TAGS,
.bbi_args = list(overwrite = TRUE, threads = 2)
)
mod_complex <- new_model(
file.path(MODEL_DIR_BBI, "acop-fake-bayes"),
.description = "complex test-test-threads model",
.tags = ORIG_TAGS,
.bbi_args = list(overwrite = TRUE, threads = 2)
)
mod_complex2 <- new_model(
file.path(MODEL_DIR_BBI, "example2_saemimp"),
.description = "complex2 test-test-threads model",
.tags = ORIG_TAGS,
.bbi_args = list(overwrite = TRUE, threads = 2)
)
mod_complex3 <- new_model(
file.path(MODEL_DIR_BBI, "iovmm"),
.description = "complex3 test-test-threads model",
.tags = ORIG_TAGS,
.bbi_args = list(overwrite = TRUE, threads = 2)
)
mod_complex4 <- new_model(
file.path(MODEL_DIR_BBI, "acop-onlysim"),
.description = "complex4 test-test-threads model",
.tags = ORIG_TAGS,
.bbi_args = list(overwrite = TRUE, threads = 2)
)
mods <- test_threads(mod1, .threads = c(2, 4), .cap_iterations = 100, .mode = "local", .dry_run = TRUE)
test_that("test_threads(.dry_run=T) creates copy models [BBR-TSTT-001]", {
mod_ctls <- lapply(mods, function(mod.x){get_model_path(mod.x)}) %>% unlist()
mod_yamls <- lapply(mods, function(mod.x){mod.x$absolute_model_path}) %>% yaml_ext()
expect_true(all(fs::file_exists(mod_ctls)))
expect_true(all(fs::file_exists(mod_yamls)))
})
test_that("test_threads(.dry_run=T) correctly changes maxeval/niter: changes only one method [BBR-TSTT-002]", {
max_evals <- get_est_options(mods)
expect_true(all(unlist(max_evals) == 100))
# Test that MAX works
mods_complex3 <- test_threads(mod_complex3, .threads = c(2, 4), .cap_iterations = 100, .mode = "local", .dry_run = TRUE)
max_evals <- get_est_options(mods_complex3) # No estimation method provided here
expect_true(all(unlist(max_evals) == 100))
})
test_that("test_threads(.dry_run=T) correctly changes maxeval/niter: changes multiple methods [BBR-TSTT-002]", {
mods_complex <- test_threads(mod_complex, .threads = c(2, 4), .cap_iterations = 100, .mode = "local", .dry_run = TRUE)
# Dont overwrite NBURN if set to 0
max_evals <- get_est_options(mods_complex)
# Confirm that MAXEVAL/NITER was preserved
for(i in seq_along(max_evals)){
max_evals_i <- unlist(max_evals[[i]])
is_nburn_opt <- grep("(?i)nburn", names(max_evals_i))
expect_true(all(max_evals_i[is_nburn_opt] == 0))
expect_true(length(is_nburn_opt) == 1)
expect_true(all(max_evals_i[!is_nburn_opt] == 100))
}
})
test_that("test_threads(.dry_run=T) correctly changes maxeval/niter: nburn is handled correctly [BBR-TSTT-002]", {
expect_message(
mods_complex2 <- test_threads(mod_complex2, .threads = c(2, 4), .cap_iterations = 100, .mode = "local", .dry_run = TRUE),
"Adding NBURN"
)
# Overwrite NBURN since was set to value other than 0
max_evals <- get_est_options(mods_complex2)
for(i in seq_along(max_evals)){
max_evals_i <- unlist(unname(max_evals[[i]]))
expect_identical(unname(max_evals_i), c(100, 100, 100, 100))
# Confirm that MAXEVAL/NITER was preserved
# This also confirms that NBURN is added when only NITER is specified (EST record 2) (recursive test)
expect_identical(names(max_evals_i), c("NITER", "NBURN", "NITER", "NBURN"))
}
})
test_that("test_threads(.dry_run=T) correctly changes maxeval/niter: keeps original if .cap_iterations = NULL [BBR-TSTT-002]", {
mods_complex <- test_threads(mod_complex, .threads = c(2, 4), .cap_iterations = NULL, .mode = "local", .dry_run = TRUE)
max_evals <- get_est_options(mods_complex)
for(i in 1:length(max_evals)){
max_evals_i <- unlist(unname(max_evals[[i]]))
expect_equal(unname(max_evals_i), c(9999, 10, 0))
expect_equal(names(max_evals_i), c("MAXEVAL", "NITER", "NBURN"))
}
})
test_that("test_threads(.dry_run=T) correctly changes maxeval/niter: warns if no $EST line found [BBR-TSTT-002]", {
expect_warning(
mods_complex4 <- test_threads(mod_complex4, .threads = c(2, 4), .cap_iterations = 4, .mode = "local", .dry_run = TRUE),
glue("No Estimation line found")
)
})
test_that("test_threads(.dry_run=T) correctly changes maxeval/niter: handles different spelling [BBR-TSTT-002]", {
# Prior to adding the `nmrec` dependency, lower case and different spellings were not supported
# Test that expected variations (defined within nmrec) are now supported
mod_complex_path <- mod_complex$absolute_model_path
mod_lines <- get_model_path(mod_complex) %>% readLines()
# replace NBURN=0 with nburn=10 (0 wont be overwritten by test_threads)
nburn_loc <- grep("(?i)NBURN", mod_lines)
mod_lines[nburn_loc] <- gsub("NBURN=0", "nburn=10", mod_lines[nburn_loc])
new_mod_name <- paste0(mod_complex_path, "_fake")
writeLines(mod_lines, ctl_ext(new_mod_name))
mod_complex_edit <- new_model(
file.path(MODEL_DIR_BBI, basename(new_mod_name)),
.tags = c("test threads"), # for deletion purposes
.bbi_args = list(overwrite = TRUE, threads = 2),
)
mods_fake <- test_threads(mod_complex_edit, .threads = c(2, 4), .cap_iterations = 5, .mode = "local", .dry_run = TRUE)
max_evals <- get_est_options(c(list(mod_complex, mod_complex_edit), mods_fake))
for(i in 1:length(max_evals)){
max_evals_i <- unlist(unname(max_evals[[i]]))
if(i == 1){ # Original model (for clarity)
expect_equal(unname(max_evals_i), c(9999, 10, 0))
expect_equal(names(max_evals_i), c("MAXEVAL", "NITER", "NBURN"))
}else if (i==2){ # modified model (NBURN=0 --> nburn=10)
expect_equal(unname(max_evals_i), c(9999, 10, 10))
expect_equal(names(max_evals_i), c("MAXEVAL", "NITER", "nburn"))
}else{ # created with test_threads (capped iterations)
expect_equal(unname(max_evals_i), c(5, 5, 5))
expect_equal(names(max_evals_i), c("MAXEVAL", "NITER", "nburn"))
}
}
delete_models(c(list(mod_complex_edit), mods_fake), .force = TRUE)
})
test_that("test_threads(.dry_run=T) threads are set correctly [BBR-TSTT-003]", {
mod_threads <- lapply(mods, function(mod.x){mod.x$bbi_args$threads}) %>% unlist()
expect_equal(mod_threads[1], 2)
expect_equal(mod_threads[2], 4)
})
test_that("check_run_times() returns NA for dry runs [BBR-CRT-007]", {
skip_if_old_bbi("3.2.0")
expect_message(
check_run_times(mod1, .wait = F),
"Could not access data for model 1"
)
run_times <- check_run_times(mod1, .wait = F) %>% suppressMessages()
expect_equal(run_times$run, "1")
expect_true(is.na(run_times$threads))
expect_true(is.na(run_times$estimation_time))
})
test_that("delete_models() default: works for models created by test_threads [BBR-CLM-001]", {
mod_ctls <- lapply(mods, function(mod.x){get_model_path(mod.x)}) %>% unlist()
mod_yamls <- lapply(mods, function(mod.x){mod.x$absolute_model_path}) %>% yaml_ext()
msg_remove <- paste0(
paste("Removed", length(mods), "model(s) with the following tags:\n"),
paste("-","test threads", collapse = "\n")
)
expect_message(
delete_models(mods, .force = T),
msg_remove, fixed = TRUE
)
expect_false(any(fs::file_exists(mod_ctls)))
expect_false(any(fs::file_exists(mod_yamls)))
})
test_that("delete_models() default: errors informatively when no test_threads tag found [BBR-CLM-001]", {
mod_fake1 <- copy_model_from(
read_model(file.path(MODEL_DIR_BBI, "1")),
"none",
.overwrite = TRUE,
.inherit_tags = FALSE
)
on.exit({
.yp <- get_yaml_path(mod_fake1)
.mp <- get_model_path(mod_fake1)
unlink(.yp)
unlink(.mp)
})
expect_error(
delete_models(mod_fake1, .force = T),
regexp = "defaults to.+test threads.+tags = NULL"
)
})
test_that("delete_models() with .tags [BBR-CLM-002]", {
mod_fake1 <- copy_model_from(
read_model(file.path(MODEL_DIR_BBI, "1")),
"none",
.overwrite = TRUE
) %>% add_tags("fake1")
mod_fake2 <- copy_model_from(
read_model(file.path(MODEL_DIR_BBI, "1")),
"both",
.overwrite = TRUE
) %>% add_tags("fake2")
mods_fake <- list(mod_fake1, mod_fake2)
fake_mod_tags <- lapply(mods_fake, function(mod.x){mod.x$tags}) %>% unlist()
msg_remove <- paste0(
paste("Removed", length(mods_fake), "model(s) with the following tags:\n"),
paste("-",fake_mod_tags, collapse = "\n")
)
mod_ctls <- lapply(mods_fake, function(mod.x){get_model_path(mod.x)}) %>% unlist()
mod_yamls <- lapply(mods_fake, function(mod.x){mod.x$absolute_model_path}) %>% yaml_ext()
expect_message(
delete_models(mods_fake, .tags = fake_mod_tags, .force = T),
msg_remove, fixed = TRUE
)
expect_false(any(fs::file_exists(mod_ctls)))
expect_false(any(fs::file_exists(mod_yamls)))
})
test_that("delete_models() with models with multiple tags [BBR-CLM-003]", {
mod_two_tags <- copy_model_from(read_model(file.path(MODEL_DIR_BBI, "1")), "two_tags") %>%
add_tags("some tag") %>% add_tags("another tag")
mod_one_tag <- copy_model_from(read_model(file.path(MODEL_DIR_BBI, "1")), "one_tag") %>%
add_tags("a tag")
mods <- list(mod_one_tag, mod_two_tags)
mod_tags <- lapply(mods, function(mod.x){mod.x$tags})
mod_tags[[2]] <- paste(mod_tags[[2]], collapse = ", ")
mod_tags <- unlist(mod_tags)
msg_remove <- paste0(
paste("Removed", length(mods), "model(s) with the following tags:\n"),
paste("-",mod_tags, collapse = "\n")
)
mod_ctls <- lapply(mods, function(mod.x){get_model_path(mod.x)}) %>% unlist()
mod_yamls <- lapply(mods, function(mod.x){mod.x$absolute_model_path}) %>% yaml_ext()
expect_message(
delete_models(mods, .tags = mod_tags, .force = T),
msg_remove, fixed = TRUE
)
expect_false(any(fs::file_exists(mod_ctls)))
expect_false(any(fs::file_exists(mod_yamls)))
})
test_that("delete_models() with .tags=NULL [BBR-CLM-004]", {
mods_threads <- test_threads(mod1, .threads = c(2, 4), .cap_iterations = 100, .mode = "local", .dry_run = TRUE)
mod_new <- copy_model_from(read_model(file.path(MODEL_DIR_BBI, "1")), "one_tag") %>%
add_tags("some tag")
mod_no_tag <- copy_model_from(read_model(file.path(MODEL_DIR_BBI, "1")), "no_tag")
mods <- c(mods_threads, list(mod_new), list(mod_no_tag))
# When using NULL, models are not necessarily deleted in order
# Only test that correct number of models are deleted
msg_remove <- paste0(
paste("Removed", length(mods), "model(s) (ignoring tags)")
)
mod_ctls <- lapply(mods, function(mod.x){get_model_path(mod.x)}) %>% unlist()
mod_yamls <- lapply(mods, function(mod.x){mod.x$absolute_model_path}) %>% yaml_ext()
expect_message(
delete_models(mods, .tags = NULL, .force = T),
msg_remove, fixed = TRUE
)
expect_false(any(fs::file_exists(mod_ctls)))
expect_false(any(fs::file_exists(mod_yamls)))
})
})
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.