|
| 1 | +#' IOin_def_pars_simple |
| 2 | +#' |
| 3 | +#' The definition file parameters to modify. This input function generates an input parameter object, either for a single simulation, |
| 4 | +#' or using simple random sampling over a set range (based on percent difference from input values). This later functionality can be put into |
| 5 | +#' a seperate funciton later if desired. |
| 6 | +#' @param ... Any number of lists, each containing 3 elements in format: list("<def file>", "<parameter name>", <value>) |
| 7 | +#' @param n The number of parameter sets to generate. |
| 8 | +#' @param pct_range The percent range of variation from input values over which sampling (if any), will happen. |
| 9 | +#' @param rm_dup TRUE/FALSE should duplicate def file + variable entries be automatically removed? A warning will occur regardless. |
| 10 | +#' |
| 11 | +#' @author Will Burke |
| 12 | +#' |
| 13 | +#' @export |
| 14 | + |
| 15 | +# pars = list(list("defs/veg_p301_conifer.def", "epc.allocation_flag","dickenson"), |
| 16 | +# list("defs/veg_p301_conifer.def", "epc.alloc_frootc_leafc", 1), |
| 17 | +# list("defs/veg_p301_conifer.def", "epc.alloc_stemc_leafc", 0.6), |
| 18 | +# list("defs/veg_p301_conifer.def", "epc.netpabs_shade", 0.2)) |
| 19 | + |
| 20 | +# --- IMPORTANT DATA ASSUMPTIONS --- |
| 21 | +# We can discuss revising this, but this code (and potentially other I(WB) write) will assume that parameters |
| 22 | +# for a single run will use the following data format (as the ultimate structure that gets passed to run_rhessys_core) |
| 23 | +# <list, length = num of unique def file params to change> |
| 24 | +# <list, length = 3, elements in order: def file path, variable name, value to be set to> |
| 25 | +# < repeat above format for each unique def file variable> |
| 26 | +# |
| 27 | +# For a set of def file parameters, regardless of how they are generated, I propose using the same format except instead of a single value |
| 28 | +# there would be a vector of values for each def file variable. Ex: |
| 29 | +# <list, length = num of unique def file params to change> |
| 30 | +# <list, length = 3, elements in order: def file path, variable name, VECTOR of values to be set to> |
| 31 | +# < repeat above format for each unique def file variable> |
| 32 | +# |
| 33 | +# Def file variables not being varied, or which don't make sense to be |
| 34 | +# (e.g. text fields like epc.allocation_flag) would need to be replicated so that each def variable list has a vector of target values |
| 35 | +# that are the same length. These can then be iterated through or lapply'd across, potentially in parallel. |
| 36 | +# |
| 37 | +# How these data structures are achieved can vary by IOin function/type of parameter variation, since different methods will require |
| 38 | +# different inputs (see the simplest option I could come up with below) |
| 39 | + |
| 40 | +IOin_def_pars_simple = function(..., n = 1, pct_range = 0.25, rm_dup = F) { |
| 41 | + |
| 42 | + pars = list(...) |
| 43 | + |
| 44 | + # if ... is already a list of lists, ie you're inputting the output of this function, unlist to keep foramt correct |
| 45 | + if (length(pars) == 1 && all(lapply(pars[[1]], length) == 3)) { |
| 46 | + pars = pars[[1]] |
| 47 | + } |
| 48 | + |
| 49 | + # some checks here, should get done regardless but mostly important for multiple param sets |
| 50 | + if (any(lapply(pars, length) != 3)) { |
| 51 | + stop("Each input list must have 3 elements - 1) file path to def file 2) def file variable 3) value") |
| 52 | + } |
| 53 | + |
| 54 | + # name some things to be helpful |
| 55 | + name_pars = function(x) { |
| 56 | + names(x) = c("Def_file", "Variable", "Value") |
| 57 | + return(x) |
| 58 | + } |
| 59 | + pars = lapply(pars, name_pars) |
| 60 | + |
| 61 | + # check for duplicate def_file + variable entries, if rm_dup is T, keep only the first |
| 62 | + file_var = paste0(sapply(pars, "[[",1), "--", sapply(pars, "[[",2)) |
| 63 | + if (length(pars[duplicated(file_var)]) > 0) { |
| 64 | + warning("There are duplicate def file + variable entries, these should be corrected before running RHESSys.") |
| 65 | + if (rm_dup) { |
| 66 | + pars[duplicated(file_var)] = NULL |
| 67 | + cat("Duplicate def file + variable entries have been removed.\n") |
| 68 | + } |
| 69 | + } |
| 70 | + |
| 71 | + if (n > 1) { |
| 72 | + # only vary the variables that are numbers |
| 73 | + values = unlist(lapply(pars, "[[", 3)) |
| 74 | + values = suppressWarnings(as.numeric(values)) |
| 75 | + #if (any(is.na(values))) { |
| 76 | + #cat() # idk guess doesn't matter |
| 77 | + #} |
| 78 | + |
| 79 | + value_sets = lapply(values[!is.na(values)], function(x) runif(n = n, min = x - (pct_range * x), max = x + (pct_range * x))) |
| 80 | + pars[!is.na(values)] = mapply(function(x, y) {x[[3]] = y; return(x)}, x = pars[!is.na(values)], y = value_sets, SIMPLIFY = F) |
| 81 | + |
| 82 | + if (any(is.na(values))) { |
| 83 | + pars[is.na(values)] = lapply(pars[is.na(values)], function(x) {x[[3]] = rep.int(x[[3]], n); return(x)}) |
| 84 | + } |
| 85 | + |
| 86 | + } |
| 87 | + |
| 88 | + return(pars) |
| 89 | + |
| 90 | +} |
0 commit comments