R/run.R

Defines functions run

Documented in run

#' Run a Stock Synthesis model
#'
#' Checks for presence of a Stock Synthesis executable and then runs the
#' model with any additional arguments specified by `extras`.
#'
#' @param dir Directory containing the model input files.
#' @template exe
#' @template extras
#' @param skipfinished Skip any folders that already contain a Report.sso file.
#' This can be helpful if the function is interrupted while running iteratively.
#' @param show_in_console Show output in the R console? If FALSE,
#' then the console output is saved to a file (specified by
#' `console_output_file`) at the end of the model run.
#' @param console_output_file File to store console output (if
#' show_in_console = FALSE).
#' @template verbose
#'
#' @return Returns one of five messages:
#' "ran model", "model run failed", "unknown run status", "not a
#' directory", or "contained Report.sso".
#'
#' @description The `run()` function checks for the executable via
#' [r4ss::check_exe()]. This involves first checking the
#' specified
#' directory `dir` for the specified SS3 executable name. If it is not
#' found in the specified
#' directory, then it checks the PATH. Linux systems may have an
#' existing executable utility `/usr/sbin/ss` in the path. If `exe =
#' "ss3"` and this file is found by [check_exe()], it will be ignored
#' based on the smaller file size relative to the SS3 executable. Linux
#' users who want to use the workflow of having SS3 in their PATH should
#' name the SS3 file something besides `ss`, such as `ss3` or
#' `ss_linux`.
#'
#' @author Ian G. Taylor, Kathryn L. Doering, Kelli F. Johnson
#' @export
#' @family run functions
#' @examples
#' \dontrun{
#' dir <- system.file("extdata", "simple_small", package = "r4ss")
#' r4ss::run(dir = dir)
#' }
#'
run <- function(dir = getwd(),
                exe = "ss3",
                extras = "",
                skipfinished = TRUE,
                show_in_console = FALSE,
                console_output_file = "console.output.txt",
                verbose = TRUE) {
  # check to make sure the first input is in the correct format
  if (!is.character(dir)) {
    stop("Input 'dir' should be a character string")
  }
  if (!is.logical(show_in_console)) {
    stop("Input 'show_in_console' should be TRUE or FALSE")
  }
  if (!show_in_console & !is.character(console_output_file)) {
    stop("Input 'console_output_file' should be a character string")
  }
  if (length(dir) > 1) {
    lifecycle::deprecate_stop(
      when = "1.46.2",
      what = "run(dir = 'must be a single directory')",
      details = "Please use the {purrr} package or other tools to apply run() to multiple directories"
    )
  }

  wd_orig <- getwd()
  on.exit(setwd(wd_orig), add = TRUE)

  # sort out path to executable
  check_exe_results <- check_exe(dir = dir, exe = exe, verbose = verbose)
  command <- check_exe_results[["exe"]]

  # confirm that dir exists
  if (!dir.exists(dir)) {
    warning("not a directory:", dir)
    results <- "not a directory"
  } else {
    if (file.exists(file.path(dir, "Report.sso")) && skipfinished) {
      # skip directories that have results in them
      message(
        "Skipping ", dir, " because it contains",
        " a Report.sso file and skipfinished = TRUE"
      )
      results <- "contained Report.sso"
    } else {
      # run model
      setwd(dir) # change working directory
      # provide some messages
      if (verbose) {
        message(
          "Changing working directory to ", dir,
          " and running model using the command: ", command, " ", extras
        )
      }
      if (!show_in_console && verbose) {
        message(
          "Input 'show_in_console' = FALSE, ",
          "so writing console output to ",
          console_output_file
        )
      }
      # call system2() to actually run the model
      console_output <- system2(
        command = command,
        args = extras,
        stdout = ifelse(show_in_console,
          "",
          TRUE
        ),
        stderr = ifelse(show_in_console,
          "",
          TRUE
        )
      )
      # write console output to file if not shown in console
      if (!show_in_console) {
        writeLines(
          c(
            "###",
            "console output",
            as.character(Sys.time()),
            "###",
            " ",
            console_output
          ),
          con = console_output_file
        )
        if (verbose) {
          message("console output written to ", console_output_file)
        }
      }
      # determine if run finished
      # console_output will either be a character vector of all the
      # lines of output, or a code returned by system2() which will be
      # 0 if the run completed with no issues
      # various other possible codes if the run fails
      results <- dplyr::case_when(
        grepl("Run has completed", tail(console_output, 1)) ~ "ran model", # 3.30.19 and earlier
        grepl("Finished running model", tail(console_output, 1)) ~ "ran model", # 3.30.20 format
        grepl("Fatal Error", tail(console_output, 5)) ~ "model run failed",
        console_output[1] == 0 ~ "ran model",
        console_output[1] > 0 ~ "model run failed",
        TRUE ~ "unknown run status"
      )
    } # end model run
  } # end code for exe present

  return(results)
}
r4ss/r4ss documentation built on April 30, 2024, 4:42 a.m.