Skip to content
Snippets Groups Projects
ogs6.R 21 KiB
Newer Older
#' OGS6
#' @description Constructor for the \code{OGS6} base class
#' @export
    #' @description
    #' Creates new OGS6 object
    #' @param sim_name string: Simulation name
    #' @param sim_path string: Path where all files for the simulation will be
    #'   saved
    #' @examples
    #' ogs6_obj <- OGS6$new(sim_name = "my_sim", sim_path = "my/path")
      self$sim_name <- sim_name

      if(missing(sim_path)){
        sim_path <- unlist(options("r2ogs6.default_sim_path"))
      self$sim_path <- sim_path
    #===== Adding components =====
    #' @description
    #' Adds a .prj simulation component
Ruben Heinrich's avatar
Ruben Heinrich committed
    #' @param x An object of any .prj `prj` class
    #' @examples
    #' ogs6_obj <- OGS6$new(sim_name = "my_sim", sim_path = "my/path")
    #' ogs6_obj$add(prj_parameter(name = "foo", type = "bar"))
    add = function(x){
      # Assert that class name is in implemented .prj classes for OGS6
      ogs6_prj_classes <- ogs6_prj_top_level_classes()
      assertthat::assert_that(class(x) %in% ogs6_prj_classes)
      # Get name of corresponding OGS6 component
      component_name <- names(ogs6_prj_classes)[ogs6_prj_classes == class(x)]
      component_class <-
        eval(parse(text = paste0("class(self$", component_name, ")")))
      active_field_call <-
        ifelse(component_class == "list",
               paste0("self$", component_name,
                      " <- c(self$", component_name, ", list(x))"),
               paste0("self$", component_name, " <- x"))

      eval(parse(text = active_field_call))

      # If class has `name` variable, make it accessable by name
      if(component_class == "list" &&
         "name" %in% names(as.list(formals(class(x))))){
        name_call <- paste0("names(self$", component_name, ")[[length(self$",
                            component_name, ")]] <- x$name")

        eval(parse(text = name_call))
      }
    #' @description
    #' Adds a reference to a file with ending .gml and optionally, a
    #' \code{OGS6_gml} object
    #' @param gml string | OGS6_gml: Either a path to a file with extension
    #' .gml or a OGS6_gml object.
    #' @examples
    #' ogs6_obj <- OGS6$new(sim_name = "my_sim", sim_path = "my/path")
    #' ogs6_obj$add_gml("this_works.gml")
    #' \dontrun{ogs6_obj$add_gml("this_doesnt.oops")}
      if(assertthat::is.string(gml)){
        assertthat::assert_that(grepl("\\.gml$", gml))
        private$.geometry <- gml
      }else{
        assertthat::assert_that(inherits(gml, "OGS6_gml"))
        private$.gml <- gml
Johannes Boog's avatar
Johannes Boog committed
        #private$.geometry <- paste0(self$sim_name, ".gml")
    #' @description
    #' Adds a reference to a \code{.vtu} file and optionally, a \code{OGS6_vtu}
    #' object
    #' @param path string: A path
    #' @param axisym flag: Is the mesh axially symmetrical?
    #' @param read_in_vtu flag: Optional: Should \code{.vtu} file just be
    #' copied or read in too?
    #' @examples
    #' ogs6_obj <- OGS6$new(sim_name = "my_sim", sim_path = "my/path")
    #' ogs6_obj$add_vtu("this_works.vtu")
    #' \dontrun{ogs6_obj$add_vtu("this_doesnt.oops")}
    add_vtu = function(path,
                       axisym = FALSE,
                       read_in_vtu = FALSE){
      assertthat::assert_that(assertthat::is.string(path))
      assertthat::assert_that(grepl("\\.vtu$", path))
      assertthat::assert_that(assertthat::is.flag(axisym))
      assertthat::assert_that(assertthat::is.flag(read_in_vtu))

      self$meshes <- c(self$meshes,
                       list(mesh = list(path = path,
                                        axially_symmetric = axisym)))
        private$.vtus <- c(private$.vtus, list(OGS6_vtu$new(path)))
    #' @description
    #' Update a component of the \code{OGS6} object.
    #' @param cmpts list(sublist, length(sublist) == 2): The first element
    #' of a sublist is a character that calls an \code{OGS6} component, the
    #' second one is the corresponding value.
    #' @examples
    #' \dontrun{ogs6_obj$update_component(list(
    #'                    list("ogs6_obj$parameters[[1]]$value", 2.3),
    #'                    list("ogs6_obj$media[[1]]$properties[[2]]$value",
    #'                         1.0e-3)))}
    update_component = function(cmpts){#cmpts=list(list(call_str, value))
        assertthat::assert_that(is.list(cmpts))

        for (i in seq_along(cmpts)){
            # check sublists
            assertthat::assert_that(is.list(cmpts[[i]]))
            assertthat::assert_that(length(cmpts[[i]])==2)
            assertthat::assert_that(is.character(cmpts[[i]][[1]]))

            # update component via call
            call_str <- cmpts[[i]][[1]]
            value <- cmpts[[i]][[2]]
            call_str <- gsub("^[A-Za-z_0-9]*\\$", "self$", call_str)
            assertthat::assert_that(!is.null(eval(parse(text = call_str))),
                                    msg = paste(call_str,
                                                "not found in ogs6_obj",
                                                self$sim_name))
            set_call <- paste0(call_str, " <- ", value)
            eval(parse(text = set_call))
        }
        invisible(self)
    },

    #===== Utility =====
    #' @description
    #' Checks if the \code{OGS6} object has all necessary parameters for
    #' starting a simulation
    #' @param print_status flag: Should the status be printed to the console?
    #' @examples
    #' ogs6_obj <- OGS6$new(sim_name = "my_sim", sim_path = "my/path")
    #' ogs6_obj$get_status()
    get_status = function(print_status = TRUE){

      assertthat::assert_that(assertthat::is.flag(print_status))
      status_strs <- character()
Ruben Heinrich's avatar
Ruben Heinrich committed
      tag_names <- lapply(get_prj_top_level_tags(), `[[`, 1)
      required <- lapply(get_prj_top_level_tags(), `[[`, 2)
      for(i in seq_len(length(tag_names))){
        is_required <- required[[i]]

        prj_obj_call <- paste0("private$.", tag_names[[i]])
        prj_obj <- eval(parse(text = prj_obj_call))

        if(length(prj_obj) == 0){
          if(is_required){
            status_str <- crayon::red("\u2717 ")
            flag <- FALSE
          }else{
            status_str <- crayon::yellow("\u2717 ")
          }
        }else{
          status_str <- crayon::green("\u2713 ")
        }

        status_str <- paste0(status_str,
                             "'",
                             tag_names[[i]],
                             ifelse(!class(prj_obj) == "list",
                                    "' is defined",
                                    "' has at least one element"))

        status_strs <- c(status_strs, status_str)
      status <- paste(status_strs, collapse = "\n")

        if(flag){
          cat(paste0("Your OGS6 object has all necessary components.\n",
Ruben Heinrich's avatar
Ruben Heinrich committed
                     "You can try calling ogs6_run_simulation().",
                     "Note that this calls more validation functions, ",
                     "so you may not be done just yet.\n"))
        }
    #' @description
    #' Overrides default printing behaviour
    print = function(){
      cat("OGS6\n")
      cat("simulation name:  ", self$sim_name, "\n", sep = "")
      cat("simulation path:  ", self$sim_path, "\n", sep = "")

      cat("\n----- geometry:  ", self$geometry, "\n", sep = "")
      cat("associated OGS6_gml:\n")
      print(self$gml)

      cat("\n----- meshes -----\n",
          paste(self$meshes, collapse = "\n"),
          "\n", sep = "")

Ruben Heinrich's avatar
Ruben Heinrich committed
      prj_tags <- lapply(get_prj_top_level_tags(), function(x){x[["tag_name"]]})
      prj_tags <- prj_tags[!prj_tags %in% c("geometry", "mesh", "meshes")]

      for(i in seq_len(length(prj_tags))){
        tag_name <- prj_tags[[i]]

        prj_param_call <- paste0("print(self$", tag_name, ")")

        cat("\n----- ", tag_name, " -----\n", sep = "")
        eval(parse(text = prj_param_call))
        cat("\n", sep = "")
      }

      invisible(self)
    },

    #' print_log
    #' @description Prints logfile to console (if it exists)
    print_log = function(){
      if(!is.null(self$logfile)){
        writeLines(readLines(self$logfile))
      }else{
        cat("There is no logfile associated with this OGS6 object.\n")
      }
    #' @description
    #' Clears components from the \code{OGS6} object
    #' @param which character: The names of the components (all by default).
    #' If you want to delete only some components, run
    #' \code{names(ogs6_prj_top_level_classes())} for the available options.
    clear = function(which){
      if(missing(which)){
        which <- names(ogs6_prj_top_level_classes())
      valid_input = names(ogs6_prj_top_level_classes())

      null_it <- c("geometry", "time_loop")

      for(i in seq_len(length(which))){
        if(!which[[i]] %in% valid_input){
          warning(paste0("Parameter '", which[[i]],
                         "' not recognized by OGS6$clear(). ",
                        "Valid parameters are:\n'",
                        paste(valid_input, sep = "", collapse = "', '"),
                        "'\nSkipping."), call. = FALSE)
          next
        }else{
          call_str <- ""
          if(which[[i]] %in% null_it){
            call_str <- paste0("private$.", which[[i]], " <- NULL")
          }else{
            call_str <- paste0("private$.", which[[i]], " <- list()")
          }
          eval(parse(text = call_str))
        }
      }
  #===== Active fields =====
      #' @field sim_name
      #' Simulation name. \code{value} must be string
      sim_name = function(value) {
        if(missing(value)) {
          private$.sim_name
        }else{
          assertthat::assert_that(assertthat::is.string(value))
          private$.sim_name <- value
        }
      #' @field sim_path
      #' Simulation path. \code{value} must be string
      sim_path = function(value) {
        if(missing(value)) {
          private$.sim_path
        }else{
          private$.sim_path <- as_dir_path(value)
      #' @field logfile
      #' Logfile path. \code{value} must be string
      logfile = function(value) {
        if(missing(value)) {
          private$.logfile
        }else{
          assertthat::assert_that(assertthat::is.string(value))
          private$.logfile <- value
        }
      },

      #' @field gml
      #' \code{.gml}. read-only
      gml = function() {
        private$.gml
      #' @field geometry
      #' \code{.prj} \code{geometry} tag. \code{value} must be string
      geometry = function(value) {
        if(missing(value)) {
          private$.geometry
        }else{
          assertthat::assert_that(is.string(value))
          private$.geometry <- value
        }
      #' @field meshes
      #' \code{.prj} \code{meshes} tag. \code{value} must be list of strings
      meshes = function(value) {
        if(missing(value)) {
          private$.meshes
        }else{
          assertthat::assert_that(is.list(value))
          lapply(value, function(x){
            assertthat::assert_that(is.list(x), length(x) == 2)
            assertthat::assert_that(assertthat::is.string(x[[1]]))
            assertthat::assert_that(assertthat::is.flag(x[[2]]))
          private$.meshes <- value
        }
      #' @field vtus
      #' \code{.vtu}s. \code{value} must be list of \code{OGS6_vtu} objects
      vtus = function(value) {
        if(missing(value)) {
          private$.vtus
        }else{
          is_wrapper_list(value,
                          ogs6_prj_top_level_classes()[["vtus"]])
      #' @field python_script
      #' \code{.prj} \code{python_script} tag. \code{value} must be string
      python_script = function(value) {
        if(missing(value)) {
          private$.python_script
        }else{
          assertthat::assert_that(assertthat::is.string(value))
          private$.python_script <- value
        }
      #' @field search_length_algorithm
      #' \code{.prj} \code{search_length_algorithm} tag. \code{value} must be
Ruben Heinrich's avatar
Ruben Heinrich committed
      #' \code{prj_search_length_algorithm} object
      search_length_algorithm = function(value) {
        if(missing(value)) {
          private$.search_length_algorithm
        }else{
          assertthat::assert_that(
            ogs6_prj_top_level_classes()[["search_length_algorithm"]] %in%
              class(value))
          private$.search_length_algorithm <- value
        }
      },

      #' @field processes
      #' \code{.prj} \code{processes} tag. \code{value} must be list of
Ruben Heinrich's avatar
Ruben Heinrich committed
      #' \code{prj_process} objects
      processes = function(value) {
        if(missing(value)) {
          private$.processes
        }else{
          # If there already is a process element
          if(length(private$.processes) > 0){
            if(ogs6_prj_top_level_classes()[["processes"]] %in%
               class(private$.processes[[1]])){
                 is_wrapper_list(value,
                                 ogs6_prj_top_level_classes()[["processes"]])
            }else{
              assertthat::assert_that(assertthat::is.string(value))
              value <- list(include = c(file = value))
            }

          }else{
            if(assertthat::is.string(value)){
              value <- list(include = c(file = value))
            }else{
              is_wrapper_list(value,
                              ogs6_prj_top_level_classes()[["processes"]])
          private$.processes <- value
        }
      #' @field time_loop
      #' \code{.prj} \code{time_loop} tag. \code{value} must be
Ruben Heinrich's avatar
Ruben Heinrich committed
      #' \code{prj_time_loop} object
      time_loop = function(value) {
        if(missing(value)) {
          private$.time_loop
        }else{
          assertthat::assert_that(
            ogs6_prj_top_level_classes()[["time_loop"]] %in%
              class(value))
          private$.time_loop <- value
        }
      #' @field local_coordinate_system
      #' \code{.prj} \code{local_coordinate_system} tag. \code{value} must be
Ruben Heinrich's avatar
Ruben Heinrich committed
      #' \code{prj_local_coordinate_system} object
      local_coordinate_system = function(value) {
        if(missing(value)) {
          private$.local_coordinate_system
        }else{
          assertthat::assert_that(
            ogs6_prj_top_level_classes()[["local_coordinate_system"]] %in%
              class(value))
          private$.local_coordinate_system <- value
        }
      #' @field media
      #' \code{.prj} \code{media} tag. \code{value} must be list of
Ruben Heinrich's avatar
Ruben Heinrich committed
      #' \code{prj_medium} objects
      media = function(value) {
        if(missing(value)) {
          private$.media
        }else{
          is_wrapper_list(value,
                          ogs6_prj_top_level_classes()[["media"]])
          private$.media <- value
        }
      #' @field parameters
      #' \code{.prj} \code{parameters} tag. \code{value} must be list of
Ruben Heinrich's avatar
Ruben Heinrich committed
      #' \code{prj_parameter} objects
      parameters = function(value) {
        if(missing(value)) {
          private$.parameters
        }else{
          is_wrapper_list(value,
                          ogs6_prj_top_level_classes()[["parameters"]])
          private$.parameters <- value
        }
      #' @field chemical_system
      #' \code{.prj} \code{chemical_system} tag. \code{value} must be
Ruben Heinrich's avatar
Ruben Heinrich committed
      #' \code{prj_chemical_system} object
      chemical_system = function(value) {
        if(missing(value)) {
          private$.chemical_system
        }else{
          assertthat::assert_that(
            ogs6_prj_top_level_classes()[["chemical_system"]] %in%
              class(value))
          private$.chemical_system <- value
        }
      },

      #' @field curves
      #' \code{.prj} \code{curves} tag. \code{value} must be list of
Ruben Heinrich's avatar
Ruben Heinrich committed
      #' \code{prj_curve} objects
      curves = function(value) {
        if(missing(value)) {
          private$.curves
        }else{
          is_wrapper_list(value,
                          ogs6_prj_top_level_classes()[["curves"]])
          private$.curves <- value
        }
      #' @field process_variables
      #' \code{.prj} \code{process_variables} tag. \code{value} must be list of
Ruben Heinrich's avatar
Ruben Heinrich committed
      #' \code{prj_process_variable} objects
      process_variables = function(value) {
        if(missing(value)) {
          private$.process_variables
        }else{
          is_wrapper_list(
            ogs6_prj_top_level_classes()[["process_variables"]])
          private$.process_variables <- value
        }
      #' @field nonlinear_solvers
      #' \code{.prj} \code{nonlinear_solvers} tag. \code{value} must be list of
Ruben Heinrich's avatar
Ruben Heinrich committed
      #' \code{prj_nonlinear_solver} objects
      nonlinear_solvers = function(value) {
        if(missing(value)) {
          private$.nonlinear_solvers
        }else{
          is_wrapper_list(
            ogs6_prj_top_level_classes()[["nonlinear_solvers"]])
          private$.nonlinear_solvers <- value
        }
      #' @field linear_solvers
      #' \code{.prj} \code{linear_solvers} tag. \code{value} must be list of
Ruben Heinrich's avatar
Ruben Heinrich committed
      #' \code{prj_linear_solver} objects
      linear_solvers = function(value) {
        if(missing(value)) {
          private$.linear_solvers
        }else{
          is_wrapper_list(value,
                          ogs6_prj_top_level_classes()[["linear_solvers"]])
          private$.linear_solvers <- value
        }
      #' @field test_definition
      #' \code{.prj} \code{test_definition} tag. \code{value} must be list of
Ruben Heinrich's avatar
Ruben Heinrich committed
      #' \code{prj_vtkdiff} objects
      test_definition = function(value) {
        if(missing(value)) {
          private$.test_definition
        }else{
          is_wrapper_list(value,
                          ogs6_prj_top_level_classes()[["test_definition"]])
          private$.test_definition <- value
        }
      #' @field insitu
      #' \code{.prj} \code{insitu} tag. \code{value} must be
Ruben Heinrich's avatar
Ruben Heinrich committed
      #' \code{prj_insitu} object
      insitu = function(value) {
        if(missing(value)) {
          private$.insitu
        }else{
          assertthat::assert_that(
            ogs6_prj_top_level_classes()[["insitu"]] %in%
              class(value))
          private$.insitu <- value
        }
      #' @field pvds
      #' \code{.pvd}s. \code{value} must be list of \code{OGS6_pvd} objects
Ruben Heinrich's avatar
Ruben Heinrich committed
      pvds = function(value) {
        if(missing(value)) {
Ruben Heinrich's avatar
Ruben Heinrich committed
          private$.pvds
Ruben Heinrich's avatar
Ruben Heinrich committed
          is_wrapper_list(value, "OGS6_pvd")
          private$.pvds <- value
      #' @field h5s
      #' \code{h5s} \code{value} must be of class \code{H5IdComponent}
      #' as returned by \code{rhdf5::h5read()}.
      h5s = function(value) {
          if(missing(value)) {
              private$.h5s
          }else{
              is_wrapper_list(value, element_class = "OGS6_h5")
              private$.h5s <- value
          }

  #===== Private parameters =====

    # general parameters
      # .vtu reference(s)
      .python_script = NULL,
      .processes = list(),
      .local_coordinate_system = NULL,
      .media = list(),
      .parameters = list(),
      .chemical_system = NULL,
      .curves = list(),
      .process_variables = list(),
      .nonlinear_solvers = list(),
      .linear_solvers = list(),
      .test_definition = list(),
Ruben Heinrich's avatar
Ruben Heinrich committed
      # .pvd objects (output)
      .pvds = NULL,
      .h5s = NULL


#===== ogs6_prj_top_level_classes =====


#' ogs6_prj_top_level_classes
#' @description Returns named character vector of \code{OGS6} top level
#' \code{.prj} tags (names) represented by \code{r2ogs6} classes along with
#' their class names (values).
#' @return character
#' @export
ogs6_prj_top_level_classes <- function(){

  xpaths_for_classes <- xpaths_for_classes

  flattened_xpaths <- unlist(xpaths_for_classes)
  names(flattened_xpaths) <- NULL

  prj_components <- character()
  seen <- character()

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

    split_xpath <-
      unlist(strsplit(flattened_xpaths[[i]], "/", fixed = TRUE))

    if(!split_xpath[[1]] %in% seen){
      if(!is.null(get_class_from_xpath(split_xpath[[1]]))){
        prj_components <- c(prj_components,
                            get_class_from_xpath(split_xpath[[1]]))

      }else{
        xpath <- paste(split_xpath[[1]], split_xpath[[2]], sep = "/")
        prj_components <- c(prj_components,
                            get_class_from_xpath(xpath))
      }

      names(prj_components)[[length(prj_components)]] <- split_xpath[[1]]
      seen <- c(seen, split_xpath[[1]])
    }
  }

  return(prj_components)
}