Skip to content

Commit

Permalink
Improve project directory setup via create_sim() (#192)
Browse files Browse the repository at this point in the history
* rename create_sim() to init_sim_project()

* change function arguments/docs to be more consistent
    * change `tests` to `init_tests`
    * change `hpc` to `init_dirs` for greater flexibility

* minor bug fixes
    *  init_sim_project(): use proj_set to activate project in current session (proj_activate activates project in new session)
    * test_sim_dir(): hide output with invisible()

* update vignettes

* closes #176 and #177
  • Loading branch information
tiffanymtang authored Jan 2, 2025
1 parent bf8b8db commit 2e86612
Show file tree
Hide file tree
Showing 12 changed files with 188 additions and 98 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,5 @@ Icon
Network Trash Folder
Temporary Items
.apdisk

vignettes/figures/figures.pptx
2 changes: 1 addition & 1 deletion NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ export(create_evaluator)
export(create_experiment)
export(create_method)
export(create_rmd)
export(create_sim)
export(create_visualizer)
export(eval_constructor)
export(eval_feature_importance)
Expand Down Expand Up @@ -50,6 +49,7 @@ export(get_save_dir)
export(get_vary_across)
export(get_visualizers)
export(init_docs)
export(init_sim_project)
export(list_col_to_chr)
export(load_all)
export(neg)
Expand Down
90 changes: 50 additions & 40 deletions R/init-dir.R
Original file line number Diff line number Diff line change
@@ -1,37 +1,36 @@
#' @title Create a simulation project
#'
#' @description `create_sim()` initializes a directory for your simulation
#' @description `init_sim_project()` initializes a directory for your simulation
#' study. It wraps around \code{usethis::create_project()}, as well as
#' \code{usethis::use_git()} and \code{renv::init()}.
#'
#' @param path A `character` specifying the path for your simulation
#' @param path Character string, specifying the path for your simulation
#' directory.
#' @param init_git A `logical` indicating whether to intialize your
#' simulation directory as a git repository.
#' @param init_renv A `logical` stating whether to initialize `renv` with
#' `init()` from the `renv` package. Defaults to `FALSE`.
#' @param tests A `logical` indicating whether to generate sub-directories
#' @param init_git Logical, indicating whether to intialize your
#' simulation directory as a git repository. Defaults to `TRUE`.
#' @param init_renv Logical, stating whether to initialize `renv` with
#' `init()` from the `renv` package. Defaults to `TRUE`.
#' @param init_tests Logical, indicating whether to generate sub-directories
#' for organizing unit tests. Defaults to `TRUE`.
#' @param hpc A `logical` indicating whether to create sub-directories for
#' organizing files related to high-power computing environments. Defaults to
#' `FALSE`.
#' @param init_dirs Character vector, specifying additional directories to
#' create in the simulation project. Defaults to `NULL`.
#'
#' @examples
#' \dontrun{
#' # create template directory for simulation project
#' create_sim("path/to/sim")}
#' init_sim_project("path/to/sim")}
#'
#' @export
create_sim <- function(
init_sim_project <- function(
path,
init_git = TRUE,
init_renv = FALSE,
tests = TRUE,
hpc = FALSE
init_renv = TRUE,
init_tests = TRUE,
init_dirs = NULL
) {
rlang::check_installed(
"usethis",
reason = "to create a simulation project with `create_sim()`"
reason = "to create a simulation project with `init_sim_project()`"
)

## ensure arguments are appropriate
Expand All @@ -44,11 +43,8 @@ create_sim <- function(
if (!is.logical(init_renv)) {
stop("init_renv must be a logical.")
}
if (!is.logical(tests)) {
stop("tests must be a logical.")
}
if (!is.logical(hpc)) {
stop("hpc must be a logical.")
if (!is.logical(init_tests)) {
stop("init_tests must be a logical.")
}

## don't overwrite existing project
Expand All @@ -64,40 +60,52 @@ create_sim <- function(

## state the necessary directories
dirs <- c(
"R", "R/dgp", "R/method", "R/eval", "R/viz", "results"
"R",
file.path("R", "dgp"),
file.path("R", "method"),
file.path("R", "eval"),
file.path("R", "viz"),
"meals",
"results"
)

## add the optional directories
if (tests) {
if (init_tests) {
dirs <- c(
dirs, "tests", "tests/testthat", "tests/testthat/dgp-tests",
"tests/testthat/method-tests", "tests/testthat/eval-tests",
"tests/testthat/viz-tests"
dirs,
"tests",
file.path("tests", "testthat"),
file.path("tests", "testthat", "dgp-tests"),
file.path("tests", "testthat", "method-tests"),
file.path("tests", "testthat", "eval-tests"),
file.path("tests", "testthat", "viz-tests")
)
}
if (hpc) {
dirs <- c(dirs, "scripts", "logs")

# add additional directories
if (!is.null(init_dirs)) {
dirs <- c(dirs, init_dirs)
}

## create the specified directories
sapply(
dirs,
function(dir) {
dir.create(path = paste(path, dir, sep = "/"), showWarnings = FALSE)
dir.create(path = file.path(path, dir), showWarnings = FALSE)
}
)

## state the necessary files
files <- c("README.md", "R/meal.R")
if (tests) {
files <- c(files, "tests/testthat.R")
files <- c("README.md", file.path("meals", "meal.R"))
if (init_tests) {
files <- c(files, file.path("tests", "testthat.R"))
}

## create the specified files
file.create(paste(path, files, sep = "/"))
file.create(file.path(path, files))

## write the header of R/meal.R
meal_file <- file(paste(path, "R/meal.R", sep = "/"))
meal_file <- file(file.path(path, "meals", "meal.R"))
writeLines(
c(
"# load required libraries",
Expand All @@ -111,7 +119,7 @@ create_sim <- function(
close(meal_file)

## write minimal template for README.md
readme_file <- file(paste(path, "README.md", sep = "/"))
readme_file <- file(file.path(path, "README.md"))
writeLines(
c(
"# Simulation Study Title",
Expand All @@ -125,8 +133,8 @@ create_sim <- function(
close(readme_file)

## write tests/testthat.R if necessary
if (tests) {
testthat_file <- file(paste(path, "tests/testthat.R", sep = "/"))
if (init_tests) {
testthat_file <- file(file.path(path, "tests", "testthat.R"))
writeLines(
c(
"library(simChef)",
Expand All @@ -143,7 +151,7 @@ create_sim <- function(

## activate the project
if (rlang::is_interactive()) {
usethis::proj_activate(path = path)
usethis::proj_set(path = path)

## initialize a git repository if asked
if (init_git) usethis::use_git()
Expand All @@ -152,9 +160,11 @@ create_sim <- function(
if (init_renv) {
rlang::check_installed(
"renv",
reason = "to initialize renv with `create_sim()`"
reason = "to initialize renv with `init_sim_project()`"
)
renv::init()
renv::init(path, bare = TRUE)
}

usethis::proj_activate(path = path)
}
}
4 changes: 2 additions & 2 deletions R/run-tests.R
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ run_tests <- function() {
#' project and if it is run when this R project is active. Additionally, tests
#' must be stored in sub-directories whose names match those suggesting in the
#' "Setting Up Your Simulation" vignette. These details are conveniently taken
#' care of when a simulation study is set up using [create_sim()].
#' care of when a simulation study is set up using [init_sim_project()].
#'
#' @examples
#' \dontrun{
Expand Down Expand Up @@ -138,5 +138,5 @@ load_all <- function() {
c("R/dgp", "R/method", "R/eval", "R/viz"),
pattern = "*.R$", full.names = TRUE, ignore.case = TRUE
)
sapply(sim_functions_files, source)
invisible(sapply(sim_functions_files, source))
}
2 changes: 1 addition & 1 deletion _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ reference:
desc: >
Functions for automatically setting up a simulation experiment directory.
contents:
- create_sim
- init_sim_project
- title: "R Markdown Report"
desc: >
Functions for summarizing and visualizing results from a simulation
Expand Down
36 changes: 0 additions & 36 deletions man/create_sim.Rd

This file was deleted.

41 changes: 41 additions & 0 deletions man/init_sim_project.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion man/test_sim_dir.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file added vignettes/figures/init_sim_project.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 31 additions & 5 deletions vignettes/simChef-full.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -1247,15 +1247,41 @@ fs::dir_tree(get_save_dir(experiment))
#> └── viz_results.rds
```

## Simulation directory template
## Simulation project template

To help with onboarding and setting up your simulation study, we have provided a helper function `create_sim()`.
To help with onboarding and setting up your simulation study, we have provided a helper function `init_sim_project()`, which initializes a ready-to-use directory for your `simChef` simulation project:

```{r create-sim, eval = FALSE}
create_sim(path = "path/to/sim/dir")
init_sim_project(path = "path/to/your/project")
```

`create_sim()` initializes a ready-to-use directory for your `simChef` simulation study.
For more information and other best practices to improve reproducibility and replicability of your simulation study, please checkout [Setting up your simulation study](simulation-directory-setup.html).
This will create a project directory with the following structure:

```{r eval = FALSE}
project/
├── .git
├── .gitignore
├── R # folder containing general R functions
│ ├── dgp ## folder containing dgp functions
│ ├── eval ## folder containing evaluation functions
│ ├── method ## folder containing method functions
│ └── viz ## folder containing visualization functions
├── README.md
├── meals # folder containing scripts to assemble/run simulation experiments
│ └── meal.R ## example script to assemble/run a simulation experiment
├── renv
├── results # folder containing results from simulation experiments
└── tests # folder containing test scripts
├── testthat
│ ├── dgp-tests ## folder containing tests for dgp functions
│ ├── eval-tests ## folder containing tests for evaluation functions
│ ├── method-tests ## folder containing tests for method functions
│ └── viz-tests ## folder containing tests for visualization functions
└── testthat.R
```

Using this project directory structure, we recommend placing your DGP, method, evaluation, and visualization functions in the appropriate subdirectories within the `R` directory to stay modular and organized. Then, to assemble and run your simulation experiment, you can write an executable *meal* script and store it in the `meals` directory. To see what this project directory structure may look like in practice for our toy simulation, check out this [GitHub repository](https://github.com/tiffanymtang/simChef-project).

Moreover, `init_sim_project()` automatically integrates your simulation project with several major reproducibility and replicability tools, including `git` (for version control), `renv` (for management of package dependencies), and `testthat` (for unit testing). For more information and other best practices to improve reproducibility and replicability of your simulation study, please see the vignette [Setting up your simulation study](simulation-directory-setup.html).

# References
Loading

0 comments on commit 2e86612

Please sign in to comment.