Skip to content
Snippets Groups Projects
sim_utils.R 18 KiB
Newer Older
  • Learn to ignore specific revisions
  • Ruben Heinrich's avatar
    Ruben Heinrich committed
    #===== ogs6_run_simulation =====
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    #' ogs6_run_simulation
    #' @description Wrapper function that calls \code{ogs6_export_sim_files()},
    #'   \code{ogs6_call_ogs6()} and \code{ogs6_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 ogs6_bin_path string: Optional: OpenGeoSys 6 executable path. Defaults
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    #'   to \code{options("r2ogs6.default_ogs6_bin_path")}
    
    #' @param overwrite flag: Should existing files be overwritten?
    
    #' @param verbose flag
    #' @export
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    ogs6_run_simulation <- function(ogs6_obj,
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                                   write_logfile = TRUE,
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                                   ogs6_bin_path,
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                                   verbose = F) {
    
        # Export (and / or copy referenced) simulation files
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
        ogs6_export_sim_files(ogs6_obj = ogs6_obj,
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                             test_mode = FALSE)
    
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
        exit_code <- ogs6_call_ogs6(ogs6_obj = ogs6_obj,
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                                   write_logfile = write_logfile,
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                                   ogs6_bin_path = ogs6_bin_path,
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                                   verbose = verbose)
    
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
        ogs6_read_output_files(ogs6_obj = ogs6_obj)
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    
    
        return(exit_code)
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    }
    
    
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    #===== ogs6_export_sim_files =====
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    
    
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    #' ogs6_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 overwrite flag: Should existing files be overwritten?
    
    #' @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
    ogs6_export_sim_files <- function(ogs6_obj,
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                                     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{
    
            if(!overwrite){
                assertthat::assert_that(length(list.files(ogs6_obj$sim_path)) == 0)
    
    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[["path"]], ogs6_obj$sim_path)
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
        })
    
        if(!is.null(ogs6_obj$python_script)){
            file.copy(ogs6_obj$python_script, ogs6_obj$sim_path)
        }
    
        export_prj(ogs6_obj)
    
        return(invisible())
    }
    
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    #===== ogs6_call_ogs6 =====
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    
    
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    #' ogs6_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 ogs6_bin_path string: Optional: Path to OpenGeoSys 6 executable or
    #'   OpenGeoSys container (singularity image) file. Defaults
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    #'   to \code{options("r2ogs6.default_ogs6_bin_path")}
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    ogs6_call_ogs6 <- function(ogs6_obj,
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                              write_logfile = TRUE,
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                              ogs6_bin_path,
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                              verbose = F){
    
        assertthat::assert_that(inherits(ogs6_obj, "OGS6"))
        assertthat::assert_that(assertthat::is.flag(write_logfile))
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
        if(missing(ogs6_bin_path)){
            ogs6_bin_path <- unlist(options("r2ogs6.default_ogs6_bin_path"))
    
        else if(is.null(ogs6_bin_path)){
            ogs6_bin_path <- unlist(options("r2ogs6.default_ogs6_bin_path"))
        }
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
        assertthat::assert_that(assertthat::is.string(ogs6_bin_path))
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
        assertthat::assert_that(assertthat::is.flag(verbose))
    
    
        # construt call to os
        prj_path_full <- paste0(ogs6_obj$sim_path,
    
                                ogs6_obj$sim_name,
                                ".prj")
    
        ogs6_args <- c(prj_path_full, "-o", ogs6_obj$sim_path)
        ogs6_command <- construct_ogs_command(ogs6_bin_path)
    
        #  reorder for using 'system2()'
        if (length(ogs6_command)>1) {
            ogs6_command_str <- ogs6_command[1]
            ogs6_args <- c(ogs6_command[-1], ogs6_args)
        } else {
            ogs6_command_str <- ogs6_command
        }
    
        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)
    
            }else{
                # If old logfile exists, delete it
                if(file.exists(ogs6_obj$logfile)){
                    file.remove(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(exit_code)
    
    
    #' construct_ogs_command
    #' @description Constructs the call string to for 'system2()'.
    #' @param ogs6_bin_path string: Optional: Path to OpenGeoSys 6 executable or
    #'   OpenGeoSys container (singularity image) file. Defaults
    #'   to \code{options("r2ogs6.default_ogs6_bin_path")}
    #'
    #' @return string: Call object.
    construct_ogs_command <- function(ogs6_bin_path){
    
        assertthat::assert_that(assertthat::is.string(ogs6_bin_path))
    
        # check if existent
        if (dir.exists(ogs6_bin_path)) {
            stop("'ogs6_bin_path' has to be an executable or container image file.",
                 call. = FALSE)
        }
        else if (!(file.exists(ogs6_bin_path))) {
            stop("'ogs6_bin_path' does not exist.'",
                 call. = FALSE)
        }
    
        # Construct the call wether ogs6_bin_path is executable or
        # container image file
        if (stringr::str_sub(ogs6_bin_path, -4) == ".sif"){
    
            assertthat::assert_that(file.exists(ogs6_bin_path))
            ogs6_command <- c("singularity","exec", "--app ogs",
                              ogs6_bin_path, "ogs")
        }
        else {
            ogs6_command <- paste0(ogs6_bin_path)
            assertthat::assert_that(file.exists(ogs6_command))
        }
    
        return(ogs6_command)
    }
    
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    #===== ogs6_read_output_files =====
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    #' ogs6_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
    ogs6_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)
    
    phit0's avatar
    phit0 committed
        # Wait for eventual file writing processes to finish
        t0 <- Sys.time()
        while(((length(pvd_paths) == 0) | any(file.size(pvd_paths) <= 64)) &
              difftime(Sys.time(), t0, units = "secs") < 2) {
            Sys.sleep(0.01)
        }
        if (((length(pvd_paths) == 0) | any(file.size(pvd_paths) <= 64)))  {
            stop("Output file not written out correctly.
                        Unable to import *.pvd")
        } else {
            ogs6_obj$pvds <- lapply(pvd_paths, function(x){OGS6_pvd$new(pvd_path = x)})
        }
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    #===== Test benchmarks =====
    
    #' Run benchmark
    #'
    #' Utility function for quick benchmark runs
    #'
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    #' @param ogs6_bin_path string:
    
    #' @param sim_path string: Path where simulation files will be saved
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                              ogs6_bin_path,
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
        if(missing(ogs6_bin_path)){
            ogs6_bin_path <- unlist(options("r2ogs6.default_ogs6_bin_path"))
    
        if(missing(sim_path)){
    
            sim_path <- unlist(options("r2ogs6.default_sim_path"))
    
        }
    
        assertthat::assert_that(assertthat::is.string(prj_path))
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
        assertthat::assert_that(assertthat::is.string(ogs6_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,
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                             sim_path = sim_path)
    
        # check if *.gml file is present
        read_gml <-  ifelse(
                        any(sapply(list.files(), function(x) grepl(".gml", x))),
                        T, F)
    
    
                    prj_path = prj_path,
                    read_in_gml = read_gml)
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
        return(invisible(ogs6_run_simulation(ogs6_obj,
                                        ogs6_bin_path = ogs6_bin_path)))
    
    #' Run benchmarks
    #'
    #' This is a wrapper function for `run_benchmark()`.
    #'
    
    #' @param path string: Path to benchmark folder
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    #' @param ogs6_processlib_path string: Path to OpenGeoSys 6 ProcessLib folder
    
    #'   which contains relevant Tests.cmake files
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    #' @param ogs6_bin_path string:
    
    #' @param sim_path string: Path where simulation files will be saved
    
    #' @param starting_from_prj_path string: `.prj` path to start from
    
    #' @param print_results flag: Print results in the end?
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                                   ogs6_processlib_path,
                                   ogs6_bin_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(ogs6_processlib_path)){
            ogs6_processlib_path <-
                unlist(options("r2ogs6.default_ogs6_processlib_path"))
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
        }
    
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
        if(missing(ogs6_bin_path)){
            ogs6_bin_path <- unlist(options("r2ogs6.default_ogs6_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(ogs6_processlib_path))
        assertthat::assert_that(assertthat::is.string(ogs6_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 <-
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
            lapply(get_benchmark_paths(ogs6_processlib_path), function(x){
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                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]],
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                                               ogs6_bin_path = ogs6_bin_path,
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                                               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
    #'
    #' Gets paths to all benchmarks that should work from `Tests.cmake` files
    #'
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    #' @param ogs6_processlib_path string: Path to OpenGeoSys 6 ProcessLib folder
    
    #'   which contains relevant `Tests.cmake` files
    #' @noRd
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    get_benchmark_paths <- function(ogs6_processlib_path){
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
    
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
        tests_cmake_files <- list.files(path = ogs6_processlib_path,
    
    Ruben Heinrich's avatar
    Ruben Heinrich committed
                                        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))