Skip to content
Snippets Groups Projects
utils.R 8.73 KiB
Newer Older
Jannes Breier's avatar
Jannes Breier committed
# function to get file extension
get_major_file_ext <- function(path) {
Jannes Breier's avatar
Jannes Breier committed
  # Get all files in path
  all_files <- list.files(
    path,
    full.names = TRUE
  )

  # Get file extensions
  all_file_types <- all_files %>%
Jannes Breier's avatar
Jannes Breier committed
    strsplit("/") %>%
    sapply(utils::tail, 1) %>%
    strsplit("\\.") %>%
Jannes Breier's avatar
Jannes Breier committed
    sapply(function(x) {
      y <- x[-1]
      if ("json" %in% y) {
        return(paste(tail(strsplit(y, "\\."), 2), collapse = "."))
      } else {
        return(tail(strsplit(y, "\\."), 1))
      }
Jannes Breier's avatar
Jannes Breier committed
    }) %>%
Jannes Breier's avatar
Jannes Breier committed

  # Get most frequent file types
Jannes Breier's avatar
Jannes Breier committed
  # TODO not yet working
Jannes Breier's avatar
Jannes Breier committed
  most_frequent <- all_file_types %>%
    factor() %>%
    table() %>%
    names() %>%
Jannes Breier's avatar
Jannes Breier committed
    .[seq_len(5)]
Jannes Breier's avatar
Jannes Breier committed

  # 5 exemplaric files to detect type
  files_to_check <- sapply(
    most_frequent,
    function(x, y, z) {
      y[which(z == x)[1]]
    },
    y = all_files,
Jannes Breier's avatar
Jannes Breier committed
    z = all_file_types
Jannes Breier's avatar
Jannes Breier committed
  # Detect actual LPJmL data type
  types <- sapply(
    files_to_check,
    lpjmlkit:::detect_io_type
  ) %>%
Jannes Breier's avatar
Jannes Breier committed
    stats::setNames(names(.), .)
Jannes Breier's avatar
Jannes Breier committed

  # Assign file type after ranking which is available
  # first preferable: "meta", second: "clm", last: "raw"
  if ("meta" %in% names(types)) {
Jannes Breier's avatar
Jannes Breier committed
    file_type <- types["meta"]
Jannes Breier's avatar
Jannes Breier committed
  } else if ("clm" %in% names(types)) {
Jannes Breier's avatar
Jannes Breier committed
    file_type <- types["clm"]
Jannes Breier's avatar
Jannes Breier committed
  } else if ("raw" %in% names(types)) {
Jannes Breier's avatar
Jannes Breier committed
    file_type <- types["raw"]
Jannes Breier's avatar
Jannes Breier committed
  }
  return(file_type)
}


# function to get absolute file names
get_filenames <- function(path, # nolint
                          output_files,
                          diff_output_files,
                          input_files,
                          file_ext) {
  file_names <- list()
  # Iterate over required outputs
  for (ofile in names(output_files)) {
Jannes Breier's avatar
Jannes Breier committed
    # Get required max. temporal resolution and convert to nstep
Jannes Breier's avatar
Jannes Breier committed
    resolution <- output_files[[ofile]]$resolution
Jannes Breier's avatar
Jannes Breier committed
    nstep <- switch(resolution,
Jannes Breier's avatar
Jannes Breier committed
      annual = 1,
      monthly = 12,
      daily = 365,
      stop(paste0("Not supported time resolution: ", dQuote(nstep), "."))
    )

    # If input file supplied use it as first priority
    if (ofile %in% names(input_files)) {
      file_name <- input_files[[ofile]]
    } else if (ofile %in% names(diff_output_files)) {
      # If different output file should be used - as second priority
      file_name <- paste0(
        path, "/",
        diff_output_files[[ofile]], ".",
        file_ext
      )
    } else {
      file_name <- NULL
    }

    if (!is.null(file_name)) {
      # Check if data could be read in
      meta <- lpjmlkit::read_meta(file_name)

      # Then check if temporal resultion of file matches required nstep
      if (nstep != meta$nstep && nstep != meta$nbands) {
        stop(
          paste0(
            "Required temporal resolution (nstep = ", nstep, ") ",
            "not supported by file ", dQuote(file_name),
            " (", meta$nstep, ")"
          )
        )
      }

Jannes Breier's avatar
Jannes Breier committed
      # If nothing specified try to read required files from provided path
Jannes Breier's avatar
Jannes Breier committed
    } else {
      # Iterate over file name options (e.g. runoff, mrunoff, ...)
Jannes Breier's avatar
Jannes Breier committed
      for (cfile in seq_along(output_files[[ofile]]$file_name)) {
        file_name <- paste0(
          path, "/",
          output_files[[ofile]]$file_name[cfile], ".",
          file_ext
        )

        # Check if file exists and if so check required temporal resolution
        # else next
        if (file.exists(file_name)) {
          meta <- lpjmlkit::read_meta(file_name)
          if (nstep <= meta$nstep || nstep == meta$nbands) {
            # Matching file found, break and use current file_name
            break
          }
        }

        # At end of iteraton raise error that no matching file_name was found
        if (cfile == length(output_files[[ofile]]$file_name) &&
Jannes Breier's avatar
Jannes Breier committed
          !output_files[[ofile]]$optional) {
Jannes Breier's avatar
Jannes Breier committed
          stop(
            paste0(
              "No matching output for ", dQuote(ofile),
              " with required temporal resolution (nstep = ", nstep, ") ",
              "found at path ", dQuote(path), "."
            )
          )
        }
      }
    }
    file_names[[ofile]] <- file_name
  }
  file_names
}


#' List required output files for given metric
#'
#' List required output files for given metric based on parameter file
#' `inst/extfiles/metric_files.yml`
#'
#' @param metric character string/list of strings. metrics to list outputs for
#'        can be one of:
#'        "all" - list all outputs for all metrics
#'        "ecorisk" - list outputs for ecorisk metric without nitrogen
#'        "ecorisk_nitrogen" - list outputs for ecorisk metric with nitrogen
#'        "biocol" - list outputs for biocol metric
#'        "biome" - list outputs for the biome classification
#' @param only_first_filename if several legal output names are listed, only
#'        output the first of them (default: TRUE)
#'
#' @return list object with required outputs, their required temporal resolution
#'         and if it is optional
#' @examples
#' \dontrun{
#' list_outputs(metric = "ecorisk_nitrogen")
#' }
#'
#' @md
#' @export
Jannes Breier's avatar
Jannes Breier committed
list_outputs <- function(metric = "all",
                         only_first_filename = TRUE) {
  metric <- process_metric(metric = metric)

  system.file(
    "extdata",
    "metric_files.yml",
    package = "biospheremetrics"
  ) %>%
    yaml::read_yaml() %>%
    get_outputs(metric, only_first_filename)
}

# List arguments of functions used in metrics from metric_files.yml
list_function_args <- function(metric = "all") {
  metric <- process_metric(metric = metric)

  system.file(
    "extdata",
    "metric_files.yml",
    package = "boundaries"
  ) %>%
    yaml::read_yaml() %>%
    get_function_args(metric)
}
Jannes Breier's avatar
Jannes Breier committed

# Translate metric options into internal metric names
process_metric <- function(metric = "all") {
  all_metrics <- c(
    "ecorisk", "ecorisk_nitrogen", "biocol", "biome"
Jannes Breier's avatar
Jannes Breier committed
  )

  if ("all" %in% metric) {
    metric <- all_metrics
  }

  metric <- match.arg(
    arg = metric,
    choices = all_metrics,
    several.ok = TRUE
  )

  metric
}


# for input list a, all duplicate keys are unified, taking the value with
#     highest temporal resolution (daily>monthly>annual)
get_outputs <- function(x, metric_name, only_first_filename) { # nolint
  outputs <- list()
  # Iterate over all metrics
  for (metric in x$metric[metric_name]) {
    # Iterate over all unique keys
    for (item in names(metric$output)) {
      # Check if output is already in list or if it has higher resolution
      if (!item %in% names(outputs) ||
Jannes Breier's avatar
Jannes Breier committed
        (item %in% names(outputs) &&
          higher_res(
            metric$output[[item]]$resolution,
            outputs[[item]]$resolution
          ))
Jannes Breier's avatar
Jannes Breier committed
      ) {
        # Assign output resolution from metric file
        outputs[[item]]$resolution <- metric$output[[item]]$resolution
        outputs[[item]]$optional <- metric$output[[item]]$optional
        # Assign output file name from metric file
        if (only_first_filename) {
          outputs[[item]]$file_name <- x$file_name[[item]][1]
        } else {
          outputs[[item]]$file_name <- x$file_name[[item]]
        }
      }
    }
  }
  outputs
}


# Get arguments of functions used in metrics
get_function_args <- function(x, metric_name) {
  # List functions of metrics (metric_name)
  funs <- list()

  for (metric in x$metric[metric_name]) {
    funs[[metric$fun_name]] <- metric$funs
  }

  # Get arguments of functions
  funs %>%
    lapply(function(x) {
      unlist(
        lapply(mget(x, inherits = TRUE), methods::formalArgs),
        use.names = FALSE
Jannes Breier's avatar
Jannes Breier committed
# Check if resolution of x is higher than resolution of y
higher_res <- function(x, y) {
  levels <- c("annual", "monthly", "daily")
  resolution_x <- match(match.arg(x, levels), levels)
  resolution_y <- match(match.arg(y, levels), levels)

  if (resolution_x > resolution_y) {
    return(TRUE)
  } else {
    return(FALSE)
  }
}

# split calculation string for variable addition/subtraction into signs & vars
split_sign <- function(string) {
  # add spaces around +- signs
  string <- gsub(
    "-",
    " - ",
    gsub("+", " + ", string, fixed = TRUE),
    fixed = TRUE
  )
  # reduce multiple spaces to one
  string <- trimws(gsub("\\s+", " ", string))
  a <- strsplit(string, " ")[[1]]
  if (length(a) == 1) {
    outarray <- array("", dim = c(1, 2))
  } else {
    outarray <- array("", dim = c(round((length(a) + 1) / 2), 2))
  for (i in seq_along(a)) {
    i2 <- floor(i / 2 + 1)
    if (i == 1 && !(grepl(a[1], "+-", fixed = TRUE))) outarray[1, 1] <- "+"
    if (grepl(a[i], "+-", fixed = TRUE)) {
      outarray[i2, 1] <- a[i]
    } else {
      outarray[i2, 2] <- a[i]
    }
  }
  colnames(outarray) <- c("sign", "variable")
  return(outarray)
}
Jannes Breier's avatar
Jannes Breier committed

DIM <- function(...) {
  lapply(args, function(x) {
    if (is.null(dim(x))) {
      return(length(x))
    }
  })[[1]]
Jannes Breier's avatar
Jannes Breier committed
# Avoid note for "."...
Jannes Breier's avatar
Jannes Breier committed
utils::globalVariables(".") # nolint:undesirable_function_linter