Skip to content
Snippets Groups Projects
sim_utils.R 15.8 KiB
Newer Older
Ruben Heinrich's avatar
Ruben Heinrich committed
#===== ogs_run_simulation =====
#' ogs_run_simulation
#' @description Wrapper function that calls \code{ogs_export_sim_files()},
#'   \code{ogs_call_ogs6()} and \code{ogs_read_output_files()}.
#' @param ogs6_obj OGS6: Simulation object
#' @param write_logfile flag: Should output be written to a logfile? If
#'   \code{FALSE}, output will be written to console. If \code{TRUE}, logfile
#'   directory will be created in \code{ogs6$sim_path} directory
#' @param ogs_bin_path string: Optional: OpenGeoSys 6 bin folder path. Defaults
#'   to \code{options("r2ogs6.default_ogs_bin_path")}
#' @param verbose flag
#' @export
Ruben Heinrich's avatar
Ruben Heinrich committed
ogs_run_simulation <- function(ogs6_obj,
                               write_logfile = TRUE,
                               ogs_bin_path,
                               verbose = F) {

    # Export (and / or copy referenced) simulation files
    ogs_export_sim_files(ogs6_obj = ogs6_obj,
                         test_mode = FALSE)

    exit_code <- ogs_call_ogs6(ogs6_obj = ogs6_obj,
                               write_logfile = write_logfile,
                               ogs_bin_path = ogs_bin_path,
                               verbose = verbose)

    ogs_read_output_files(ogs6_obj = ogs6_obj)

    return(invisible(exit_code))
}


#===== ogs_export_sim_files =====


#' ogs_export_sim_files
#' @description Creates \code{ogs6$sim_path} directory if it does not exist yet
#'   and exports and / or copies all simulation files to it.
#' @param ogs6_obj OGS6: Simulation object
#' @param test_mode flag: If \code{TRUE}, Will not check status of
#'   \code{ogs6_obj} before exporting files. Defaults to \code{FALSE}
#' @export
Ruben Heinrich's avatar
Ruben Heinrich committed
ogs_export_sim_files <- function(ogs6_obj,
                                 test_mode = FALSE){
    assertthat::assert_that(inherits(ogs6_obj, "OGS6"))
Ruben Heinrich's avatar
Ruben Heinrich committed
    assertthat::assert_that(assertthat::is.flag(test_mode))
Ruben Heinrich's avatar
Ruben Heinrich committed
    if(!test_mode &&
       !ogs6_obj$get_status(print_status = FALSE)){
        stop("There are some components missing from your OGS6 object.",
             call. = FALSE)
    }
    # Create the simulation folder
    if (!dir.exists(ogs6_obj$sim_path)) {
        dir.create(ogs6_obj$sim_path)
    } else{
Ruben Heinrich's avatar
Ruben Heinrich committed
        if (length(list.files(ogs6_obj$sim_path)) != 0) {
Ruben Heinrich's avatar
Ruben Heinrich committed
                paste0("sim_path directory '", ogs6_obj$sim_path,
                       "' is not empty. Files may be overwritten."
Ruben Heinrich's avatar
Ruben Heinrich committed
    if(!is.null(ogs6_obj$gml)){
        export_gml(ogs6_obj$gml,
                   paste0(ogs6_obj$sim_path, basename(ogs6_obj$geometry)))
    }else if(!is.null(ogs6_obj$geometry)){
        file.copy(ogs6_obj$geometry, ogs6_obj$sim_path)
    }

    # If processes tag only contains reference, copy referenced file
    if(names(ogs6_obj$processes)[[1]] == "include"){

        include_dir <- paste0(ogs6_obj$sim_path, "include/")

        if(!dir.exists(include_dir)){
            dir.create(include_dir)
        }

        file.copy(ogs6_obj$processes[[1]][["file"]], include_dir)

        new_ref_path <- paste0(include_dir,
                               basename(ogs6_obj$processes[[1]][["file"]]))

        ogs6_obj$processes <- new_ref_path
    }

    # Copy all referenced .vtu files to ogs6_obj$sim_path
    lapply(ogs6_obj$meshes, function(x){
        file.copy(x, ogs6_obj$sim_path)
    })

    if(!is.null(ogs6_obj$python_script)){
        file.copy(ogs6_obj$python_script, ogs6_obj$sim_path)
    }

    export_prj(ogs6_obj)

    return(invisible())
}

#===== ogs_call_ogs6 =====


#' ogs_call_ogs6
#' @description Makes system call to OpenGeoSys 6 and retrieves exit code.
#' @param ogs6_obj OGS6: Simulation object
#' @param write_logfile flag: Should output be written to a logfile? If
#'   \code{FALSE}, output will be written to console. If \code{TRUE}, logfile
#'   directory will be created in \code{ogs6$sim_path} directory
#' @param ogs_bin_path string: Optional: OpenGeoSys 6 bin folder path. Defaults
#'   to \code{options("r2ogs6.default_ogs_bin_path")}
#' @param verbose flag
#' @export
Ruben Heinrich's avatar
Ruben Heinrich committed
ogs_call_ogs6 <- function(ogs6_obj,
                          write_logfile = TRUE,
                          ogs_bin_path,
                          verbose = F){

    assertthat::assert_that(inherits(ogs6_obj, "OGS6"))
    assertthat::assert_that(assertthat::is.flag(write_logfile))
    if(missing(ogs_bin_path)){
        ogs_bin_path <- unlist(options("r2ogs6.default_ogs_bin_path"))
    }

Ruben Heinrich's avatar
Ruben Heinrich committed
    assertthat::assert_that(assertthat::is.string(ogs_bin_path))
    assertthat::assert_that(assertthat::is.flag(verbose))

    # Construct the call
Ruben Heinrich's avatar
Ruben Heinrich committed
    exe_str <- ifelse(Sys.info()["sysname"] == "Windows",
                      "ogs.exe",
                      "ogs")

    ogs6_command_str <- paste0(ogs_bin_path, exe_str)
    sim_path_full <- paste0(ogs6_obj$sim_path,
                            ogs6_obj$sim_name,
                            ".prj")
    ogs6_args <- c(sim_path_full, "-o", ogs6_obj$sim_path)
    exit_code <- 0
    # Finally, make the system call to start the simulation
    if (write_logfile) {
        # Create logfile directory
        logfile_dir <- paste0(ogs6_obj$sim_path, "logfiles/")
        # Set logfile parameter of simulation object
        ogs6_obj$logfile <- paste0(logfile_dir, ogs6_obj$sim_name, "_log.txt")
        if(!dir.exists(logfile_dir)){
            dir.create(logfile_dir)
        }
        assertthat::assert_that(!file.exists(ogs6_obj$logfile))
        file.create(ogs6_obj$logfile)
Ruben Heinrich's avatar
Ruben Heinrich committed
        if(verbose){
            cat("\nRunning simulation '", ogs6_obj$sim_name, "'\n", sep = "")
        }
        exit_code <- system2(command = ogs6_command_str,
                             args = ogs6_args,
                             stdout = ogs6_obj$logfile)
    } else{
        exit_code <- system2(command = ogs6_command_str,
                             args = ogs6_args)
    return(invisible(exit_code))
Ruben Heinrich's avatar
Ruben Heinrich committed
#===== ogs_read_output_files =====
#' ogs_read_output_files
#' @description Read in generated \code{.pvd} files and add it to ogs6_obj
#' @param ogs6_obj OGS6: Simulation object
#' @export
Ruben Heinrich's avatar
Ruben Heinrich committed
ogs_read_output_files <- function(ogs6_obj){

    assertthat::assert_that(inherits(ogs6_obj, "OGS6"))

Ruben Heinrich's avatar
Ruben Heinrich committed
    pvd_paths <- list.files(ogs6_obj$sim_path,
                            "\\.pvd$",
                            full.names = TRUE)
Ruben Heinrich's avatar
Ruben Heinrich committed
    for(i in seq_len(length(pvd_paths))){
        ogs6_obj$pvds <- c(ogs6_obj$pvds,
                           list(OGS6_pvd$new(pvd_path = pvd_paths[[i]])))
Ruben Heinrich's avatar
Ruben Heinrich committed
#===== Test benchmarks =====
#' run_benchmark
#' @description Utility function for quick benchmark runs
#' @param prj_path string:
#' @param ogs_bin_path string:
#' @param sim_path string: Path where simulation files will be saved
run_benchmark <- function(prj_path,
                          ogs_bin_path,
                          sim_path){

    if(missing(ogs_bin_path)){
        ogs_bin_path <- unlist(options("r2ogs6.default_ogs_bin_path"))
    if(missing(sim_path)){
        sim_path <- unlist(options("r2ogs6.default_sim_path"))
    }

    assertthat::assert_that(assertthat::is.string(prj_path))
    assertthat::assert_that(assertthat::is.string(ogs_bin_path))
    assertthat::assert_that(assertthat::is.string(sim_path))

    sim_name <- tools::file_path_sans_ext(basename(prj_path))

    ogs6_obj <- OGS6$new(sim_name = sim_name,
                         sim_id = 1,
Ruben Heinrich's avatar
Ruben Heinrich committed
                         sim_path = sim_path)
Ruben Heinrich's avatar
Ruben Heinrich committed
                prj_path = prj_path)
Ruben Heinrich's avatar
Ruben Heinrich committed
    return(invisible(ogs_run_simulation(ogs6_obj,
                                    ogs_bin_path = ogs_bin_path)))
#' run_all_benchmarks
#' @description Utility function, for quick benchmark runs. Calls
#'   run_benchmark internally.
#' @param path string: Path to benchmark folder
#' @param ogs_processlib_path string: Path to OpenGeoSys 6 ProcessLib folder
#'   which contains relevant Tests.cmake files
#' @param ogs_bin_path string:
#' @param sim_path string: Path where simulation files will be saved
#' @param starting_from_prj_path string: \code{.prj} path to start from
#' @param print_results flag: Print results in the end?
Ruben Heinrich's avatar
Ruben Heinrich committed
                               ogs_processlib_path,
Ruben Heinrich's avatar
Ruben Heinrich committed
                               print_results = TRUE){
        path <- unlist(options("r2ogs6.default_benchmark_path"))
Ruben Heinrich's avatar
Ruben Heinrich committed
    if(missing(ogs_processlib_path)){
        ogs_processlib_path <-
            unlist(options("r2ogs6.default_ogs_processlib_path"))
    }

    if(missing(ogs_bin_path)){
        ogs_bin_path <- unlist(options("r2ogs6.default_ogs_bin_path"))
    if(missing(sim_path)){
        sim_path <- unlist(options("r2ogs6.default_sim_path"))
    }

    assertthat::assert_that(assertthat::is.string(path))
Ruben Heinrich's avatar
Ruben Heinrich committed
    assertthat::assert_that(assertthat::is.string(ogs_processlib_path))
    assertthat::assert_that(assertthat::is.string(ogs_bin_path))
    assertthat::assert_that(assertthat::is.string(sim_path))
    assertthat::assert_that(assertthat::is.string(starting_from_prj_path))
Ruben Heinrich's avatar
Ruben Heinrich committed
    assertthat::assert_that(assertthat::is.flag(print_results))
Ruben Heinrich's avatar
Ruben Heinrich committed
    # Get relevant .prj paths from ProcessLib Tests.cmake files
    prj_paths <-
        lapply(get_benchmark_paths(ogs_processlib_path), function(x){
            paste0(path, x)
        })
Ruben Heinrich's avatar
Ruben Heinrich committed
    assertthat::assert_that(length(prj_paths) > 0)

    # If we know the benchmarks up to a specific file are working, skip them
    if(starting_from_prj_path != ""){

        if(is.na(match(starting_from_prj_path, prj_paths))){
            warning(paste("Couldn't find path to start from.",
                          "Returning all paths."),
                    call. = FALSE)
        }else{
            start_index <- match(starting_from_prj_path, prj_paths)
            prj_paths <- prj_paths[start_index:length(prj_paths)]
        }
Ruben Heinrich's avatar
Ruben Heinrich committed

    # Filter nonexisting files from prj_paths
    nonexisting_prj_paths <- prj_paths[!file.exists(prj_paths)]
    prj_paths <- prj_paths[!prj_paths %in% nonexisting_prj_paths]


    # Filter invalid XML from prj_paths
    invalid_xml_paths <- filter_invalid_xml(prj_paths)
    prj_paths <- prj_paths[!prj_paths %in% invalid_xml_paths]

    # Read in valid .prj files and try to run simulations
    failed_paths <- character()
    exit_codes <- numeric()
Ruben Heinrich's avatar
Ruben Heinrich committed

        cat("\nAttempting to run Benchmark", prj_paths[[i]])

        sim_name <- tools::file_path_sans_ext(basename(prj_paths[[i]]))

        sim_subdir_path <- paste0(sim_path,
                                  basename(dirname(prj_paths[[i]])),
                                  "_",
                                  sim_name)

        out<- tryCatch(
Ruben Heinrich's avatar
Ruben Heinrich committed
                exit_code <- run_benchmark(prj_path = prj_paths[[i]],
                                           ogs_bin_path = ogs_bin_path,
                                           sim_path = sim_subdir_path)
Ruben Heinrich's avatar
Ruben Heinrich committed
                exit_codes <<- c(exit_codes, exit_code)
            },
Ruben Heinrich's avatar
Ruben Heinrich committed
                message(paste("\nrun_benchmark() failed for",
                              prj_paths[[i]], ". Original error message:"))
                message(cond)
                failed_paths <<- c(failed_paths, prj_paths[[i]])
Ruben Heinrich's avatar
Ruben Heinrich committed
    run_started_paths <- prj_paths[!prj_paths %in% failed_paths]
Ruben Heinrich's avatar
Ruben Heinrich committed
    if(print_results){
        print_run_all_benchmarks(
            nonexisting_prj_paths,
            invalid_xml_paths,
            failed_paths,
            run_started_paths,
            exit_codes)
    }
Ruben Heinrich's avatar
Ruben Heinrich committed
    return(invisible(list(nonexisting_prj_paths = nonexisting_prj_paths,
                          invalid_xml_paths = invalid_xml_paths,
                          failed_paths = failed_paths,
                          run_started_paths = run_started_paths,
                          exit_codes = exit_codes)))
}
Ruben Heinrich's avatar
Ruben Heinrich committed
print_run_all_benchmarks <- function(nonexisting_prj_paths,
                                     invalid_xml_paths,
                                     failed_paths,
                                     run_started_paths,
                                     exit_codes) {
Ruben Heinrich's avatar
Ruben Heinrich committed

    if(length(nonexisting_prj_paths) > 0){
        cat("\nCould not find the following .prj files ",
            "referenced in Tests.cmake:\n",
            paste(nonexisting_prj_paths, collapse = "\n"), "\n", sep = "")
    }

    if(length(invalid_xml_paths) > 0){
        cat("\nCould not parse the following .prj files as XML:\n",
            paste(invalid_xml_paths, collapse = "\n"), "\n", sep = "")
    }

    if(length(failed_paths) > 0){
        cat("\nThere was something else wrong with the following .prj files:\n",
            paste(failed_paths, collapse = "\n"), "\n", sep = "")
Ruben Heinrich's avatar
Ruben Heinrich committed
    if(length(exit_codes) > 0){
        cat("\nOpenGeoSys produced the following exit codes:\n",
            paste(run_started_paths,
                  exit_codes,
                  sep = " produced exit code ",
                  collapse = "\n"), "\n", sep = "")
    }

    return(invisible())
}


#' get_benchmark_paths
#' @description Gets paths to all benchmarks that should work
#' @param ogs_processlib_path string: Path to OpenGeoSys 6 ProcessLib folder
#'   which contains relevant Tests.cmake files
Ruben Heinrich's avatar
Ruben Heinrich committed
get_benchmark_paths <- function(ogs_processlib_path){

    tests_cmake_files <- list.files(path = ogs_processlib_path,
                                    pattern = "^Tests\\.cmake$",
                                    recursive = TRUE,
                                    full.names = TRUE)

    benchmark_paths <- list()

    for(i in seq_len(length(tests_cmake_files))){

        file_content <- readLines(tests_cmake_files[[i]])
        file_content <- paste(file_content[!grepl("^#", file_content)],
                              collapse = "\n")

        # Get AddTest blocks
        add_test_blocks <-
            stringr::str_extract_all(file_content,
                                     "AddTest\\([^\\)]*\\)",
                                     simplify = TRUE)

        mesh_sizes <- character()

        if(grepl("foreach(mesh_size", file_content, fixed = TRUE)){

            foreach_start <-
                stringr::str_extract(file_content,
                                     "foreach\\(mesh_size[^\\)]*\\)")
            foreach_content <-
                stringr::str_remove_all(foreach_start,
                                        "(foreach\\(mesh_size )|(\\))")

            mesh_sizes <- unlist(strsplit(foreach_content, " "))
        }

        # Get .prj paths from blocks
        for(j in seq_len(length(add_test_blocks))){

            atb <- add_test_blocks[[j]]

            benchmark_dir <- stringr::str_extract(atb,
                                                  "PATH[:space:]*[^ ]*")
            benchmark_dir <-
                stringr::str_remove_all(benchmark_dir,
                                        "^PATH|[:space:]")

            prj_filename <-
                stringr::str_extract(atb,
                                     "EXECUTABLE_ARGS [^ ]*")

            prj_filename <-
                stringr::str_remove_all(prj_filename,
                                        "^EXECUTABLE_ARGS |[:space:]")

            # We just take the first size so far, eventally put loop here later
            if(length(mesh_sizes) != 0){
                prj_filename <- gsub("${mesh_size}",
                                     mesh_sizes[[1]],
                                     prj_filename,
                                     fixed = TRUE)
            }

            benchmark_path <- paste0(benchmark_dir, "/", prj_filename)

            # cat("Benchmark path: ", benchmark_path, "\n",
            #     "Test.cmake file:", tests_cmake_files[[i]], "\n")

            benchmark_paths <- c(benchmark_paths, benchmark_path)
        }
Ruben Heinrich's avatar
Ruben Heinrich committed
    return(unique(benchmark_paths))