From 7e648e6bec87e213f6526944ad8cbabc6a6f5051 Mon Sep 17 00:00:00 2001 From: dschlaep Date: Mon, 10 Jun 2019 14:32:16 -0400 Subject: [PATCH 01/21] New function `dbOutput_add_calculated_field` - function `dbOutput_add_calculated_field`: Add new field(s) to a table in \var{dbOutput} that is/are based on a calculation of values from (an) existing field(s) - documented with example code - unit test --- NAMESPACE | 1 + R/OutputDatabase_DataAccess.R | 143 ++++++++++++++++++ man/calc_RequestedSoilLayers.Rd | 2 +- man/dbOutput_add_calculated_field.Rd | 79 ++++++++++ .../testthat/test_OutputDatabase_DataAccess.R | 39 +++++ 5 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 R/OutputDatabase_DataAccess.R create mode 100644 man/dbOutput_add_calculated_field.Rd create mode 100644 tests/testthat/test_OutputDatabase_DataAccess.R diff --git a/NAMESPACE b/NAMESPACE index c794294a..7b0a3280 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -37,6 +37,7 @@ export(dbOutput_ListDesignTables) export(dbOutput_ListInternalTables) export(dbOutput_ListOutputTables) export(dbOutput_Tables_have_SoilLayers) +export(dbOutput_add_calculated_field) export(dbOutput_subset) export(dbOutput_update_OverallAggregationTable) export(dbWork_Ntodo) diff --git a/R/OutputDatabase_DataAccess.R b/R/OutputDatabase_DataAccess.R new file mode 100644 index 00000000..469a7a76 --- /dev/null +++ b/R/OutputDatabase_DataAccess.R @@ -0,0 +1,143 @@ +#------------------------------------------------------------------------------# + +#------CODE developed and written by +# - Daniel R Schlaepfer (dschlaep@uwyo.edu, drs): 2009-2016 +# for contact and further information see also: +# \url{sites.google.com/site/drschlaepfer} + +#------DISCLAIMER: This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +#------------------------------------------------------------------------------# + +#' Add new field(s) to a table in \var{dbOutput} that is/are based on a +#' calculation of values from (an) existing field(s) +#' +#' @param dbOut_fname A character string. The path to the output database. +#' @param table A character string. The table name to which the new field(s) +#' should be appended. +#' @param vars_orig A vector of character strings. The existing field names +#' that are used by \code{FUN} to calculate \code{vars_new}. +#' @param vars_new A vector of character strings. The names of new fields. +#' The number must match the number of columns returned by \code{FUN}. +#' @param FUN A function. See details. +#' @param ... Additional named arguments to \code{FUN}. See details. +#' @param verbose A logical value. +#' @param chunk_size An integer value. +#' +#' @section Details: The first argument of \code{FUN} must be a two-dimensional +#' object. This object contains the extracted values from \code{dbOut_fname}, +#' i.e., it has up to \code{chunk_size} rows and the columns are +#' \code{vars_orig}. Additional arguments can be passed via \code{...}. +#' The function must return a value (or values) corresponding to +#' \code{vars_new} for each row. These values are inserted into the new +#' field(s). +#' +#' @return The function is called for its side-effects on \code{dbOut_fname}. +#' +#' @examples +#' # Prepare databse +#' dbOut_tmp <- tempfile(fileext = ".sqlite") +#' con <- dbConnect(SQLite(), dbOut_tmp) +#' data(iris) +#' x <- data.frame(P_id = seq_len(nrow(iris)), iris) +#' dbWriteTable(con, "iris", x) +#' +#' # Define calculation function +#' vars_orig <- c("Sepal.Length", "Sepal.Width") +#' example_calc <- function(x, delta = 1, ...) { +#' apply(x, MARGIN = 1, function(x) delta * prod(x)) +#' } +#' +#' # Create new field based on a calculation +#' dbOutput_add_calculated_field( +#' dbOut_fname = dbOut_tmp, +#' table = "iris", +#' vars_orig = vars_orig, +#' vars_new = "calc", +#' FUN = example_calc, delta = 2) +#' +#' # Check the new field +#' xout <- dbReadTable(con, "iris") +#' res2 <- example_calc(x[, vars_orig], delta = 2) +#' all.equal(xout[, "calc"], res2) +#' +#' # Cleanup +#' dbDisconnect(con) +#' unlink(dbOut_tmp) +#' +#' @export +dbOutput_add_calculated_field <- function(dbOut_fname, table, + vars_orig, vars_new, FUN, ..., verbose = FALSE, chunk_size = 1e5) { + + #--- Preparations + con <- dbConnect(SQLite(), dbname = dbOut_fname) + on.exit(dbDisconnect(con), add = TRUE) + + tableq <- dbQuoteIdentifier(con, table) + vars_newq <- dbQuoteIdentifier(con, vars_new) + vars_origq <- dbQuoteIdentifier(con, vars_orig) + + has_fields <- dbListFields(con, tableq) + + # Check that `vars_orig` are available + stopifnot(vars_orig %in% has_fields) + + # Check new variable(s) don't already exist + stopifnot(!(vars_new %in% has_fields)) + + + #--- Add new variables as empty fields + sql <- paste( + "ALTER TABLE", tableq, + "ADD COLUMN", paste0(vars_newq, " REAL", collapse = ", ")) + + dbExecute(con, sql) + + + #--- Calculate new variable(s) + + # Loop over chunks, extract `vars_orig`, calculate `vars_new`, and insert + sql <- paste("SELECT \"P_id\" FROM", tableq) + pids <- as.integer(dbGetQuery(con, sql)[, 1]) + n_todos <- length(pids) + do_chunks <- parallel::splitIndices(n_todos, ceiling(n_todos / chunk_size)) + + # Prepare SQL statement to extract `vars_orig` + sql_get <- paste( + "SELECT", paste(vars_origq, collapse = ", "), + "FROM", tableq, + "WHERE \"P_id\" IN (:pids_chunk)", + "ORDER BY \"P_id\"") + + # Prepare SQL statements to insert `vars_new` + sql_put <- paste0( + "UPDATE ", tableq, " ", + "SET (", paste0(vars_newq, collapse = ", "), ") = (:res) ", + "WHERE P_id = :pids_chunk") + + # Loop over chunks + for (k in seq_along(do_chunks)) { + if (verbose) { + print(paste0(Sys.time(), ": step ", k, "/", length(do_chunks))) + } + + dbWithTransaction(con, { + # Extract data + rs_get <- dbSendStatement(con, sql_get) + dbBind(rs_get, params = list(pids_chunk = pids[do_chunks[[k]]])) + x <- dbFetch(rs_get) + dbClearResult(rs_get) + + # Calculate + res <- do.call(FUN, args = list(x, ...)) + + # Store in new variable(s) + rs_put <- dbSendStatement(con, sql_put) + dbBind(rs_put, params = list( + res = res, + pids_chunk = pids[do_chunks[[k]]])) + dbClearResult(rs_put) + }) + } +} diff --git a/man/calc_RequestedSoilLayers.Rd b/man/calc_RequestedSoilLayers.Rd index e13e0fd6..452bdf60 100644 --- a/man/calc_RequestedSoilLayers.Rd +++ b/man/calc_RequestedSoilLayers.Rd @@ -6,7 +6,7 @@ soil data input file} \usage{ calc_RequestedSoilLayers(SFSW2_prj_meta, SFSW2_prj_inputs, runIDs_adjust, - verbose = FALSE) + keep_old_depth = TRUE, verbose = FALSE) } \description{ Add soil layers (by interpolation) if not already present and store in diff --git a/man/dbOutput_add_calculated_field.Rd b/man/dbOutput_add_calculated_field.Rd new file mode 100644 index 00000000..d53311ae --- /dev/null +++ b/man/dbOutput_add_calculated_field.Rd @@ -0,0 +1,79 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/OutputDatabase_DataAccess.R +\name{dbOutput_add_calculated_field} +\alias{dbOutput_add_calculated_field} +\title{Add new field(s) to a table in \var{dbOutput} that is/are based on a +calculation of values from (an) existing field(s)} +\usage{ +dbOutput_add_calculated_field(dbOut_fname, table, vars_orig, vars_new, FUN, + ..., verbose = FALSE, chunk_size = 1e+05) +} +\arguments{ +\item{dbOut_fname}{A character string. The path to the output database.} + +\item{table}{A character string. The table name to which the new field(s) +should be appended.} + +\item{vars_orig}{A vector of character strings. The existing field names +that are used by \code{FUN} to calculate \code{vars_new}.} + +\item{vars_new}{A vector of character strings. The names of new fields. +The number must match the number of columns returned by \code{FUN}.} + +\item{FUN}{A function. See details.} + +\item{...}{Additional named arguments to \code{FUN}. See details.} + +\item{verbose}{A logical value.} + +\item{chunk_size}{An integer value.} +} +\value{ +The function is called for its side-effects on \code{dbOut_fname}. +} +\description{ +Add new field(s) to a table in \var{dbOutput} that is/are based on a +calculation of values from (an) existing field(s) +} +\section{Details}{ + The first argument of \code{FUN} must be a two-dimensional + object. This object contains the extracted values from \code{dbOut_fname}, + i.e., it has up to \code{chunk_size} rows and the columns are + \code{vars_orig}. Additional arguments can be passed via \code{...}. + The function must return a value (or values) corresponding to + \code{vars_new} for each row. These values are inserted into the new + field(s). +} + +\examples{ +# Prepare databse +dbOut_tmp <- tempfile(fileext = ".sqlite") +con <- dbConnect(SQLite(), dbOut_tmp) +data(iris) +x <- data.frame(P_id = seq_len(nrow(iris)), iris) +dbWriteTable(con, "iris", x) + +# Define calculation function +vars_orig <- c("Sepal.Length", "Sepal.Width") +example_calc <- function(x, delta = 1, ...) { + apply(x, MARGIN = 1, function(x) delta * prod(x)) +} + +# Create new field based on a calculation +dbOutput_add_calculated_field( + dbOut_fname = dbOut_tmp, + table = "iris", + vars_orig = vars_orig, + vars_new = "calc", + FUN = example_calc, delta = 2) + +# Check the new field +xout <- dbReadTable(con, "iris") +res2 <- example_calc(x[, vars_orig], delta = 2) +all.equal(xout[, "calc"], res2) + +# Cleanup +dbDisconnect(con) +unlink(dbOut_tmp) + +} diff --git a/tests/testthat/test_OutputDatabase_DataAccess.R b/tests/testthat/test_OutputDatabase_DataAccess.R new file mode 100644 index 00000000..a315a851 --- /dev/null +++ b/tests/testthat/test_OutputDatabase_DataAccess.R @@ -0,0 +1,39 @@ +context("Output: dbOutput data access functionality") + + +#--- Inputs +utils::data(list = "iris", package = "datasets") + +#--- Tests +test_that("dbOutput_add_calculated_field:", { + # Prepare databse + dbOut_tmp <- tempfile(fileext = ".sqlite") + con <- dbConnect(SQLite(), dbOut_tmp) + data(iris) + x <- data.frame(P_id = seq_len(nrow(iris)), iris) + dbWriteTable(con, "iris", x) + + # Test 1: 2 variables -> 1 variable, 1 additional parameter + # Define function + vars_orig <- c("Sepal.Length", "Sepal.Width") + example_calc <- function(x, delta = 1, ...) { + apply(x, MARGIN = 1, function(x) delta * prod(x)) + } + + # Create new field based on a calculation + dbOutput_add_calculated_field( + dbOut_fname = dbOut_tmp, + table = "iris", + vars_orig = vars_orig, + vars_new = "calc1", + FUN = example_calc, delta = 2) + + # Check the new field + xout <- dbReadTable(con, "iris") + res2 <- example_calc(x[, vars_orig], delta = 2) + expect_equivalent(xout[, "calc1"], res2) + + # Cleanup + dbDisconnect(con) + unlink(dbOut_tmp) +}) From 3d366d53220d27e39d0e0f35c53ffe651bf104ff Mon Sep 17 00:00:00 2001 From: dschlaep Date: Tue, 18 Jun 2019 12:09:24 -0400 Subject: [PATCH 02/21] "overwrite" argument for function `dbOutput_add_calculated_field` argument "overwrite" replaces content of a previously existing field instead of failing to add a new field to the database --- R/OutputDatabase_DataAccess.R | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/R/OutputDatabase_DataAccess.R b/R/OutputDatabase_DataAccess.R index 469a7a76..44356046 100644 --- a/R/OutputDatabase_DataAccess.R +++ b/R/OutputDatabase_DataAccess.R @@ -22,6 +22,10 @@ #' The number must match the number of columns returned by \code{FUN}. #' @param FUN A function. See details. #' @param ... Additional named arguments to \code{FUN}. See details. +#' @param overwrite A logical value. If \code{vars_new} already exists and +#' \code{overwrite} is \code{TRUE}, then the content of the fields +#' \code{vars_new} will be replaced. If \code{vars_new} already exists and +#' \code{overwrite} is \code{FALSE}, then the function stops with an error. #' @param verbose A logical value. #' @param chunk_size An integer value. #' @@ -68,7 +72,8 @@ #' #' @export dbOutput_add_calculated_field <- function(dbOut_fname, table, - vars_orig, vars_new, FUN, ..., verbose = FALSE, chunk_size = 1e5) { + vars_orig, vars_new, FUN, ..., overwrite = FALSE, verbose = FALSE, + chunk_size = 1e5) { #--- Preparations con <- dbConnect(SQLite(), dbname = dbOut_fname) @@ -84,15 +89,22 @@ dbOutput_add_calculated_field <- function(dbOut_fname, table, stopifnot(vars_orig %in% has_fields) # Check new variable(s) don't already exist - stopifnot(!(vars_new %in% has_fields)) + has_new <- vars_new %in% has_fields + if (has_new) { + if (!overwrite) { + stop("Requested variable(s): ", paste(shQuote(vars_new), collapse = ", "), + " already exist(s) as field(s) in database.") + } - #--- Add new variables as empty fields - sql <- paste( - "ALTER TABLE", tableq, - "ADD COLUMN", paste0(vars_newq, " REAL", collapse = ", ")) + } else { + #--- Add new variables + sql <- paste( + "ALTER TABLE", tableq, + "ADD COLUMN", paste0(vars_newq, " REAL", collapse = ", ")) - dbExecute(con, sql) + dbExecute(con, sql) + } #--- Calculate new variable(s) From 53d9bb002f6e2a7f9f7eee9e1468795409212fe2 Mon Sep 17 00:00:00 2001 From: dschlaep Date: Mon, 15 Jul 2019 11:49:16 -0400 Subject: [PATCH 03/21] New function `dbOut_read_variables_from_scenario` - Reads variables/fields from the header view or from tables including sites, runs and one of the overall aggregation tables for one of the scenarios and optionally subsets rows by a where-clause - deprecates `get.SeveralOverallVariables_Scenario` which only read from the overall aggregation tables --- NAMESPACE | 2 + R/OutputDatabase.R | 153 +++++++++++++++++- man/dbOut_read_variables_from_scenario.Rd | 35 ++++ man/dbOutput_add_calculated_field.Rd | 7 +- ...et.SeveralOverallVariables_Scenario_old.Rd | 14 ++ 5 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 man/dbOut_read_variables_from_scenario.Rd create mode 100644 man/get.SeveralOverallVariables_Scenario_old.Rd diff --git a/NAMESPACE b/NAMESPACE index 7b0a3280..d1e94b3c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -32,6 +32,7 @@ export(crs_units) export(dbConnect2) export(dbExecute2) export(dbOut_check_values) +export(dbOut_read_variables_from_scenario) export(dbOut_update_values) export(dbOutput_ListDesignTables) export(dbOutput_ListInternalTables) @@ -81,6 +82,7 @@ export(germination_wait_times) export(get.SeveralOverallVariables) export(get.SeveralOverallVariables_Ensemble) export(get.SeveralOverallVariables_Scenario) +export(get.SeveralOverallVariables_Scenario_old) export(get.Table) export(get.Table_Ensemble) export(get.Table_Scenario) diff --git a/R/OutputDatabase.R b/R/OutputDatabase.R index fd75fbde..11cde638 100644 --- a/R/OutputDatabase.R +++ b/R/OutputDatabase.R @@ -262,7 +262,7 @@ get_fieldnames <- function(responseName, fields.header, fields.iTable) { #' Get data of variables in the overall aggregation table for one of the #' scenarios #' @export -get.SeveralOverallVariables_Scenario <- function(fdbrSFSW2, responseName, # nolint +get.SeveralOverallVariables_Scenario_old <- function(fdbrSFSW2, responseName, # nolint MeanOrSD = "Mean", scenario = "Current", whereClause = NULL) { dat <- NULL @@ -311,6 +311,157 @@ get.SeveralOverallVariables_Scenario <- function(fdbrSFSW2, responseName, # noli dat[, iColumns[["outOrder"]]] } + +#' Get data of variables in the overall aggregation table for one of the +#' scenarios +#' @export +get.SeveralOverallVariables_Scenario <- function(fdbrSFSW2, responseName, # nolint + MeanOrSD = "Mean", scenario = "Current", whereClause = NULL) { + + .Deprecated("dbOut_read_variables_from_scenario") + + dbOut_read_variables_from_scenario( + fname_dbOut = fdbrSFSW2, + variables = responseName, + MeanOrSD = MeanOrSD, + scenario = scenario, + whereClause = whereClause) +} + + +#' Reads variables/fields from the header view or from tables including sites, +#' runs and one of the overall aggregation tables for one of the scenarios +#' and optionally subsets rows by a where-clause +#' +#' @param fname_dbOut A character string. The path to the output database. +#' @param variables A vector of character strings. The (partial) names of +#' variables/columns/fields to be read. +#' @param MeanOrSD A character string. Identify which type of overall aggregated +#' table to read. +#' @param scenario A character string. This must be one of the values from the +#' \var{Scenario} values from the \var{header} view. +#' @param whereClause A character string. This must be of the structure +#' \var{field_name='value'} or \code{NULL} +#' +#' @return A \code{data.frame} +#' +#' @export +dbOut_read_variables_from_scenario <- function(fname_dbOut, variables = NULL, + MeanOrSD = c("Mean", "SD"), scenario = "Current", whereClause = NULL) { + + MeanOrSD <- match.arg(MeanOrSD) + + dat <- as.data.frame(matrix(NA, nrow = 0, ncol = length(variables), + dimnames = list(NULL, variables))) + + if (length(variables) > 0) { + con <- dbConnect(SQLite(), fname_dbOut, flags = SQLITE_RO) + on.exit(dbDisconnect(con), add = TRUE) + + db_tables <- dbListTables(con) + header_fields <- dbListFields(con, "header") + + extract_tables <- c("header", "sites", "runs", paste0("overall_", MeanOrSD)) + db_setup <- lapply(extract_tables, function(table) { + tn <- grep(table, db_tables, ignore.case = TRUE, fixed = FALSE, + value = TRUE) + has <- length(tn) > 0 + icols <- if (has) get_fieldnames(variables, + fields.header = header_fields, + fields.iTable = dbListFields(con, tn)) + c(list(name = dbQuoteIdentifier(con, tn), has = has), icols = icols) + }) + names(db_setup) <- extract_tables + + has_columns <- sapply(db_setup, function(x) + x[["has"]] && x[["icols.has_columns"]]) + add_Pid <- any(sapply(db_setup, function(x) + x[["has"]] && x[["icols.addPid"]])) + outOrder <- unlist(lapply(db_setup, function(x) x[["icols.outOrder"]])) + + if (any(has_columns) || add_Pid) { + need_sep <- FALSE + + sql <- paste0("SELECT ", + # Add `P_id` if requested + if (add_Pid) { + need_sep <- TRUE + "header.P_id AS P_id" + }, + if (add_Pid && any(has_columns)) ", ", + + # Add fields from header table if requested + if (length(db_setup[["header"]][["icols.header"]]) > 0) { + temp <- dbQuoteIdentifier(con, + db_setup[["header"]][["icols.header"]]) + temp <- paste0("header.", temp, " AS ", temp, collapse = ", ") + if (need_sep) { + paste(",", temp) + } else { + need_sep <- TRUE + temp + } + }, + + # Add fields from runs table if requested + if (length(db_setup[["runs"]][["icols.iTable"]]) > 0) { + temp <- dbQuoteIdentifier(con, + db_setup[["runs"]][["icols.iTable"]]) + temp <- paste0("runs.", temp, " AS ", temp, collapse = ", ") + if (need_sep) { + paste(",", temp) + } else { + need_sep <- TRUE + temp + } + }, + + # Add fields from sites table if requested + if (length(db_setup[["sites"]][["icols.iTable"]]) > 0) { + temp <- dbQuoteIdentifier(con, + db_setup[["sites"]][["icols.iTable"]]) + temp <- paste0("sites.", temp, " AS ", temp, collapse = ", ") + if (need_sep) { + paste(",", temp) + } else { + need_sep <- TRUE + temp + } + }, + + # Add fields from aggregation output table if requested + if (length(db_setup[[4]][["icols.iTable"]]) > 0) { + temp <- dbQuoteIdentifier(con, + db_setup[[4]][["icols.iTable"]]) + temp <- paste0(db_setup[[4]][["name"]], ".", temp, " AS ", temp, + collapse = ", ") + if (need_sep) { + paste(",", temp) + } else { + temp + } + }, + + " FROM header", + " INNER JOIN ", db_setup[[4]][["name"]], + " ON header.P_id = ", db_setup[[4]][["name"]], ".P_id", + " INNER JOIN runs ON header.P_id = runs.P_id", + " INNER JOIN sites ON runs.site_id = sites.id", + " WHERE header.Scenario = ", shQuote(scenario), + if (length(whereClause) > 0) + paste0(" AND ", addHeaderToWhereClause(whereClause, + headers = header_fields)), + " ORDER BY header.P_id") + + dat <- dbGetQuery(con, sql)[, outOrder] + } + } + + dat +} + + + #' Get data of variables in the overall aggregation table for one of the #' ensembles #' @export diff --git a/man/dbOut_read_variables_from_scenario.Rd b/man/dbOut_read_variables_from_scenario.Rd new file mode 100644 index 00000000..fe7691b6 --- /dev/null +++ b/man/dbOut_read_variables_from_scenario.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/OutputDatabase.R +\name{dbOut_read_variables_from_scenario} +\alias{dbOut_read_variables_from_scenario} +\title{Reads variables/fields from the header view or from tables including sites, +runs and one of the overall aggregation tables for one of the scenarios +and optionally subsets rows by a where-clause} +\usage{ +dbOut_read_variables_from_scenario(fname_dbOut, variables = NULL, + MeanOrSD = c("Mean", "SD"), scenario = "Current", + whereClause = NULL) +} +\arguments{ +\item{fname_dbOut}{A character string. The path to the output database.} + +\item{variables}{A vector of character strings. The (partial) names of +variables/columns/fields to be read.} + +\item{MeanOrSD}{A character string. Identify which type of overall aggregated +table to read.} + +\item{scenario}{A character string. This must be one of the values from the +\var{Scenario} values from the \var{header} view.} + +\item{whereClause}{A character string. This must be of the structure +\var{field_name='value'} or \code{NULL}} +} +\value{ +A \code{data.frame} +} +\description{ +Reads variables/fields from the header view or from tables including sites, +runs and one of the overall aggregation tables for one of the scenarios +and optionally subsets rows by a where-clause +} diff --git a/man/dbOutput_add_calculated_field.Rd b/man/dbOutput_add_calculated_field.Rd index d53311ae..d6176e31 100644 --- a/man/dbOutput_add_calculated_field.Rd +++ b/man/dbOutput_add_calculated_field.Rd @@ -6,7 +6,7 @@ calculation of values from (an) existing field(s)} \usage{ dbOutput_add_calculated_field(dbOut_fname, table, vars_orig, vars_new, FUN, - ..., verbose = FALSE, chunk_size = 1e+05) + ..., overwrite = FALSE, verbose = FALSE, chunk_size = 1e+05) } \arguments{ \item{dbOut_fname}{A character string. The path to the output database.} @@ -24,6 +24,11 @@ The number must match the number of columns returned by \code{FUN}.} \item{...}{Additional named arguments to \code{FUN}. See details.} +\item{overwrite}{A logical value. If \code{vars_new} already exists and +\code{overwrite} is \code{TRUE}, then the content of the fields +\code{vars_new} will be replaced. If \code{vars_new} already exists and +\code{overwrite} is \code{FALSE}, then the function stops with an error.} + \item{verbose}{A logical value.} \item{chunk_size}{An integer value.} diff --git a/man/get.SeveralOverallVariables_Scenario_old.Rd b/man/get.SeveralOverallVariables_Scenario_old.Rd new file mode 100644 index 00000000..a53d9096 --- /dev/null +++ b/man/get.SeveralOverallVariables_Scenario_old.Rd @@ -0,0 +1,14 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/OutputDatabase.R +\name{get.SeveralOverallVariables_Scenario_old} +\alias{get.SeveralOverallVariables_Scenario_old} +\title{Get data of variables in the overall aggregation table for one of the +scenarios} +\usage{ +get.SeveralOverallVariables_Scenario_old(fdbrSFSW2, responseName, + MeanOrSD = "Mean", scenario = "Current", whereClause = NULL) +} +\description{ +Get data of variables in the overall aggregation table for one of the +scenarios +} From 8d6b68d78ac5bcc49ac24a8b17879acb95363c81 Mon Sep 17 00:00:00 2001 From: dschlaep Date: Fri, 19 Jul 2019 11:57:17 -0400 Subject: [PATCH 04/21] New circular functions: addition and subtraction --- NAMESPACE | 2 + R/Mathematical_Functions.R | 84 +++++++++++++++++++++++++++++++++ man/calc_RequestedSoilLayers.Rd | 2 +- man/circ_add.Rd | 31 ++++++++++++ man/circ_minus.Rd | 36 ++++++++++++++ 5 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 man/circ_add.Rd create mode 100644 man/circ_minus.Rd diff --git a/NAMESPACE b/NAMESPACE index c794294a..ed016a48 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -22,6 +22,8 @@ export(check_monotonic_increase) export(check_outputDB_completeness) export(check_rSFSW2_project_input_data) export(check_weatherDB) +export(circ_add) +export(circ_minus) export(climscen_metadata) export(compare_test_output) export(compare_two_dbOutput) diff --git a/R/Mathematical_Functions.R b/R/Mathematical_Functions.R index 627f33a2..ee5afa3c 100644 --- a/R/Mathematical_Functions.R +++ b/R/Mathematical_Functions.R @@ -99,6 +99,90 @@ circ_sd <- function(x, int, na.rm = FALSE) { } } + +#' Calculate the circular subtraction \var{x - y} +#' +#' @param x A numeric vector or array. +#' @param y A numeric vector or array. +#' @param int A numeric value. The number of units of \code{x} in a full circle, +#' e.g., for unit days: \code{int = 365}; for unit months: \code{int = 12}. +#' @examples +#' # Days of year +#' circ_minus(260, 240, int = 365) ## expected: +20 +#' circ_minus(240, 260, int = 365) ## expected: -20 +#' circ_minus(10, 360, int = 365) ## expected: +15 +#' circ_minus(360, 10, int = 365) ## expected: -15 +#' circ_minus(0, 360, int = 365) ## expected: +5 +#' circ_minus(360, 0, int = 365) ## expected: -5 +#' +#' # Matrix examples +#' x <- matrix(c(260, 240, 10, 360, 0, 360), nrow = 3, ncol = 2) +#' y <- matrix(c(240, 260, 360, 10, 360, 0), nrow = 3, ncol = 2) +#' circ_minus(x, y, int = 365) +#' y2 <- y +#' y2[1, 1] <- NA +#' circ_minus(y2, x, int = 365) +#' @export +circ_minus <- function(x, y, int) { + stopifnot(all(dim(x) == dim(y))) + + if (requireNamespace("circular", quietly = TRUE)) { + circ <- 2 * pi / int + d_circ <- circular::circular((x - y) * circ, + type = "angles", units = "radians", rotation = "clock", modulo = "asis") + res <- as.numeric(circular::minusPiPlusPi(d_circ) / circ) + + } else { + res <- rep(NA, length(x)) + } + + if (is.array(x)) { + array(res, dim = dim(x), dimnames = dimnames(x)) + } else { + res + } +} + + +#' Calculate the circular addition \var{x + y} +#' +#' @param x A numeric vector or array. +#' @param y A numeric vector or array. +#' @param int A numeric value. The number of units of \code{x} in a full circle, +#' e.g., for unit days: \code{int = 365}; for unit months: \code{int = 12}. +#' @examples +#' # Matrix examples: day of year +#' x <- matrix(c(260, 240, 10, 360, 0, 360), nrow = 3, ncol = 2) +#' y <- matrix(c(240, 260, 360, 10, 360, 0), nrow = 3, ncol = 2) +#' circ_add(x, y, int = 365) +#' +#' # Circular addition and subtraction +#' r1 <- circ_add(circ_minus(x, y, int = 365), y, int = 365) +#' r2 <- circ_minus(circ_add(x, y, int = 365), y, int = 365) +#' all.equal(r1, r2) +#' +#' @export +circ_add <- function(x, y, int) { + stopifnot(all(dim(x) == dim(y))) + + if (requireNamespace("circular", quietly = TRUE)) { + circ <- 2 * pi / int + d_circ <- circular::circular((x + y) * circ, + type = "angles", units = "radians", rotation = "clock", modulo = "asis") + res <- as.numeric(circular::minusPiPlusPi(d_circ) / circ) + + } else { + res <- rep(NA, length(x)) + } + + if (is.array(x)) { + array(res, dim = dim(x), dimnames = dimnames(x)) + } else { + res + } +} + + #' Find the \code{k}-largest/smallest values (and apply a function to these #' values) #' diff --git a/man/calc_RequestedSoilLayers.Rd b/man/calc_RequestedSoilLayers.Rd index e13e0fd6..452bdf60 100644 --- a/man/calc_RequestedSoilLayers.Rd +++ b/man/calc_RequestedSoilLayers.Rd @@ -6,7 +6,7 @@ soil data input file} \usage{ calc_RequestedSoilLayers(SFSW2_prj_meta, SFSW2_prj_inputs, runIDs_adjust, - verbose = FALSE) + keep_old_depth = TRUE, verbose = FALSE) } \description{ Add soil layers (by interpolation) if not already present and store in diff --git a/man/circ_add.Rd b/man/circ_add.Rd new file mode 100644 index 00000000..1c754c23 --- /dev/null +++ b/man/circ_add.Rd @@ -0,0 +1,31 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Mathematical_Functions.R +\name{circ_add} +\alias{circ_add} +\title{Calculate the circular addition \var{x + y}} +\usage{ +circ_add(x, y, int) +} +\arguments{ +\item{x}{A numeric vector or array.} + +\item{y}{A numeric vector or array.} + +\item{int}{A numeric value. The number of units of \code{x} in a full circle, +e.g., for unit days: \code{int = 365}; for unit months: \code{int = 12}.} +} +\description{ +Calculate the circular addition \var{x + y} +} +\examples{ +# Matrix examples: day of year +x <- matrix(c(260, 240, 10, 360, 0, 360), nrow = 3, ncol = 2) +y <- matrix(c(240, 260, 360, 10, 360, 0), nrow = 3, ncol = 2) +circ_add(x, y, int = 365) + +# Circular addition and subtraction +r1 <- circ_add(circ_minus(x, y, int = 365), y, int = 365) +r2 <- circ_minus(circ_add(x, y, int = 365), y, int = 365) +all.equal(r1, r2) + +} diff --git a/man/circ_minus.Rd b/man/circ_minus.Rd new file mode 100644 index 00000000..8e5b3c71 --- /dev/null +++ b/man/circ_minus.Rd @@ -0,0 +1,36 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Mathematical_Functions.R +\name{circ_minus} +\alias{circ_minus} +\title{Calculate the circular subtraction \var{x - y}} +\usage{ +circ_minus(x, y, int) +} +\arguments{ +\item{x}{A numeric vector or array.} + +\item{y}{A numeric vector or array.} + +\item{int}{A numeric value. The number of units of \code{x} in a full circle, +e.g., for unit days: \code{int = 365}; for unit months: \code{int = 12}.} +} +\description{ +Calculate the circular subtraction \var{x - y} +} +\examples{ +# Days of year +circ_minus(260, 240, int = 365) ## expected: +20 +circ_minus(240, 260, int = 365) ## expected: -20 +circ_minus(10, 360, int = 365) ## expected: +15 +circ_minus(360, 10, int = 365) ## expected: -15 +circ_minus(0, 360, int = 365) ## expected: +5 +circ_minus(360, 0, int = 365) ## expected: -5 + +# Matrix examples +x <- matrix(c(260, 240, 10, 360, 0, 360), nrow = 3, ncol = 2) +y <- matrix(c(240, 260, 360, 10, 360, 0), nrow = 3, ncol = 2) +circ_minus(x, y, int = 365) +y2 <- y +y2[1, 1] <- NA +circ_minus(y2, x, int = 365) +} From 97f44045efb51d1debb71bf9d2c5ab9b0540f0fc Mon Sep 17 00:00:00 2001 From: dschlaep Date: Fri, 19 Jul 2019 13:14:43 -0400 Subject: [PATCH 05/21] New function to calculate Trewartha climate classification --- R/Miscellaneous_Functions.R | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/R/Miscellaneous_Functions.R b/R/Miscellaneous_Functions.R index a6fc3a9a..5e34d85e 100644 --- a/R/Miscellaneous_Functions.R +++ b/R/Miscellaneous_Functions.R @@ -459,6 +459,48 @@ calc_drylandindices <- function(annualPPT, annualPET, monthlyTemp, } +#' Main climate classification according to Trewartha +#' +#' The main climate classifications based on mean monthly temperature, i.e., +#' without group B--dry, include \describe{ +#' \item Group A (tropical): sum(months >= 18 C) == 12 +#' \item Group C (subtropical): +#' sum(months >= 10 C) >= 8 & sum(months >= 18 C) < 12 +#' \item Group D (temperate and continental): sum(months >= 10 C) %in% 4:7 +#' \item Group E (boreal): sum(months >= 10 C) %in% 1:3 +#' \item Group F (polar): sum(months >= 10 C) == 0 +#' } +#' +#' @param meanTmonthly_C A numeric vector of length 12. Mean monthly air +#' temperature in degree Celsius. +#' +#' @seealso \code{\link[ClimClass](koeppen_geiger)} +#' @references Trewartha, G.T. and Lyle, H.H., 1980: An Introduction to Climate. +#' MacGraw - Hill, 5th Ed. Appendix: Koeppen's Classification of Climates +trewartha_climate <- function(meanTmonthly_C) { + stopifnot(length(meanTmonthly_C) == 12) + + temp18 <- sum(meanTmonthly_C >= 18) + + if (temp18 == 12) { + "tropical" + } else { + temp10 <- sum(meanTmonthly_C >= 10) + + if (temp10 >= 8) { + "subtropical" + } else if (temp10 >= 4) { + "temperate" + } else if (temp10 >= 1) { + "boreal" + } else { + "polar" + } + } +} + + + extreme_values_and_doys <- function(x, na.rm = FALSE) { tmax <- max(x, na.rm = na.rm) tmin <- min(x, na.rm = na.rm) From fa13fe9f486c26489a9aad38e73d717b0bbe96b9 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Mon, 30 Sep 2019 11:27:08 -0400 Subject: [PATCH 06/21] Fix function `do_OneSite` - remove object `soilTUpper` only if it exists --- R/Simulation_Run.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/R/Simulation_Run.R b/R/Simulation_Run.R index aefdd5d2..598451db 100644 --- a/R/Simulation_Run.R +++ b/R/Simulation_Run.R @@ -1271,8 +1271,9 @@ do_OneSite <- function(i_sim, i_SWRunInformation, i_sw_input_soillayers, #- Initial soil temperatures adjusted to climatic conditions print_debug(opt_verbosity, tag_simpidfid, "creating", "soil temperature") - if (exists("soilTUpper")) + if (exists("soilTUpper")) { rm(soilTUpper) + } if (prj_todos[["EstimateConstantSoilTemperatureAtUpperAndLowerBoundaryAsMeanAnnualAirTemperature"]]) { rSOILWAT2::swSite_SoilTemperatureConsts(swRunScenariosData[[sc]])["ConstMeanAirTemp"] <- mean(SiteClimate_Scenario$meanMonthlyTempC) From c3fac6bc53e10fa6f3a54f206a303640a4c12b50 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Mon, 30 Sep 2019 11:32:52 -0400 Subject: [PATCH 07/21] Fix function `dbOut_read_variables_from_scenario` - previously, if `add_Pid` and `any(has_columns`) were true, then two commas (instead of one) were inserted into the sql statement --- R/OutputDatabase.R | 1 - 1 file changed, 1 deletion(-) diff --git a/R/OutputDatabase.R b/R/OutputDatabase.R index 11cde638..30440def 100644 --- a/R/OutputDatabase.R +++ b/R/OutputDatabase.R @@ -388,7 +388,6 @@ dbOut_read_variables_from_scenario <- function(fname_dbOut, variables = NULL, need_sep <- TRUE "header.P_id AS P_id" }, - if (add_Pid && any(has_columns)) ", ", # Add fields from header table if requested if (length(db_setup[["header"]][["icols.header"]]) > 0) { From 680ea8c7db1f512cff9282a323edd64c7c78c6df Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Fri, 11 Oct 2019 15:13:25 -0400 Subject: [PATCH 08/21] Improve function `calc.ScenarioWeather` - new function `rbind_2cols_nonoverlapping`: rbind two objects, but make sure that there is no duplication in two indicator columns --> used in function `calc.ScenarioWeather` to align extracted monthly data without overlap --- R/ExtractData_ClimateDownscaling.R | 80 +++++++++++++++++++++++++++--- 1 file changed, 72 insertions(+), 8 deletions(-) diff --git a/R/ExtractData_ClimateDownscaling.R b/R/ExtractData_ClimateDownscaling.R index 6891a559..4a730a1d 100644 --- a/R/ExtractData_ClimateDownscaling.R +++ b/R/ExtractData_ClimateDownscaling.R @@ -650,6 +650,59 @@ applyDeltas2 <- function(daily, monthly, years, delta_ts, ppt_fun, } +#' \code{rbind} two objects, but make sure that there is no duplication in two +#' indicator columns. +#' +#' @param x1 A two dimensional numeric object; the first two columns (e.g., +#' years, months) are matched up against \code{x2}. +#' @param x2 Same as \code{x1}. +#' +#' @return The object that would result from \code{rbind(x1, x2)} but where +#' any duplication, as determined by the first two columns, is resolved, i.e., +#' copy with \code{NAs} is ignored or arithmetic mean across \code{x1} and +#' \code{x2}. +rbind_2cols_nonoverlapping <- function(x1, x2) { + if (is.null(x1) || nrow(x1) == 0) { + res <- x2 + + } else if (is.null(x2) || nrow(x2) == 0) { + res <- x1 + + } else { + # Check whether there is a year-month overlap + ids1 <- apply(x1[, 1:2], 1, paste, collapse = "-") + ids2 <- apply(x2[, 1:2], 1, paste, collapse = "-") + + idso1 <- ids1 %in% ids2 + if (any(idso1)) { + # handle overlap + idso2 <- ids2 %in% ids1 + + # Check whether there is one uniquely non-NA set + if (all(is.na(x1[idso1, -(1:2)]))) { + res <- rbind(x1[!idso1, ], x2) + + } else if (all(is.na(x2[idso2, -(1:2)]))) { + res <- rbind(x1, x2[!idso2, ]) + + } else { + # both sets have values for overlap: take mean + tmp <- x1 + tmp[idso1, -(1:2)] <- + (x1[idso1, -(1:2)] + x2[idso2, -(1:2)]) / 2 + res <- rbind(tmp, x2[!idso2, -(1:2)]) + } + + } else { + # there is no overlap + res <- rbind(x1, x2) + } + } + + res +} + + #' Downscale and temporal disaggregation #' @@ -2384,12 +2437,17 @@ calc.ScenarioWeather <- function(i, ig, il, gcm, site_id, i_tag, clim_source, # not provide data for the last month of a time slice (e.g. December 2005 may be NA) scen.hist.monthly <- NULL if (!all(df_wdataOut[["downscaling"]][k] == "raw")) { - for (itt in which(assocYears[["historical"]]$first)) - scen.hist.monthly <- rbind(scen.hist.monthly, scen.monthly[1, itt][[1]]) + for (itt in which(assocYears[["historical"]]$first)) { + scen.hist.monthly <- rbind_2cols_nonoverlapping( + scen.hist.monthly, + scen.monthly[1, itt][[1]]) + } - for (itt in which(assocYears[["historical"]]$second)) - scen.hist.monthly <- rbind(scen.hist.monthly, + for (itt in which(assocYears[["historical"]]$second)) { + scen.hist.monthly <- rbind_2cols_nonoverlapping( + scen.hist.monthly, scen.monthly[1 + ir, getYears$n_first + itt][[1]]) + } } if (print.debug && !is.null(scen.hist.monthly)) { @@ -2403,11 +2461,17 @@ calc.ScenarioWeather <- function(i, ig, il, gcm, site_id, i_tag, clim_source, # Put future data together scen.fut.monthly <- NULL - for (itt in which(assocYears[[df_wdataOut[["tag"]][k]]]$first)) - scen.fut.monthly <- rbind(scen.fut.monthly, scen.monthly[1, itt][[1]]) + for (itt in which(assocYears[[df_wdataOut[["tag"]][k]]]$first)) { + scen.fut.monthly <- rbind_2cols_nonoverlapping( + scen.fut.monthly, + scen.monthly[1, itt][[1]]) + } - for (itt in which(assocYears[[df_wdataOut[["tag"]][k]]]$second)) - scen.fut.monthly <- rbind(scen.fut.monthly, scen.monthly[1 + ir, getYears$n_first + itt][[1]]) + for (itt in which(assocYears[[df_wdataOut[["tag"]][k]]]$second)) { + scen.fut.monthly <- rbind_2cols_nonoverlapping( + scen.fut.monthly, + scen.monthly[1 + ir, getYears$n_first + itt][[1]]) + } if (print.debug) { scen.fut.monthly_mean <- stats::aggregate(scen.fut.monthly[, -(1:2)], From f4b1a00db33b610d53ecce5de9d4bc07b3dece0c Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Sun, 13 Oct 2019 16:24:35 -0400 Subject: [PATCH 09/21] Fix function `dbOutput_create_Design`: design & experimental treatments - function `dbOutput_create_Design` was misaligning values from the experimental treatment input file if both design and experimental treatments were active (and overlapping) --> make sure that assignment uses the same columns as the experimental treatments have --- R/OutputDatabase.R | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/R/OutputDatabase.R b/R/OutputDatabase.R index 30440def..b3141015 100644 --- a/R/OutputDatabase.R +++ b/R/OutputDatabase.R @@ -2353,9 +2353,7 @@ dbOutput_create_Design <- function(con_dbOut, SFSW2_prj_meta, #Get experimental_label_id db_combined_exp_treatments[irows, "experimental_id"] <- irows2 #insert all of the rows from experimentals - temp <- db_treatments_column_types[ - db_treatments_column_types[, "table"] == 1, "column"] - db_combined_exp_treatments[irows, temp] <- db_experimentals[irows2, ] + db_combined_exp_treatments[irows, SFSW2_prj_inputs[["create_experimentals"]]] <- db_experimentals[irows2, ] } } } else { From 84f914539a2e19633e6433cd9c7a5a7c8b572cdf Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Sun, 13 Oct 2019 16:34:46 -0400 Subject: [PATCH 10/21] Fix function `recreate_dbWork`: create_Design`: design & experimental treatments - function `recreate_dbWork` inferred `expN` (number of experimental treatments) incorrectly if both design and experimental treatments were active (and overlapping) --> number of experiment treatments is the number of treatment_labels --- R/WorkDatabase.R | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/R/WorkDatabase.R b/R/WorkDatabase.R index 428146bc..04db45c0 100644 --- a/R/WorkDatabase.R +++ b/R/WorkDatabase.R @@ -869,8 +869,6 @@ recreate_dbWork <- function(path, dbOutput, use_granular_control, out_tables <- dbOutput_ListOutputTables(con = con_dbOut) # Extract information from dbOutput table 'runs' - infer_expN <- as.integer(dbGetQuery(con_dbOut, - "SELECT MAX(treatment_id) FROM runs")) infer_scN <- as.integer(dbGetQuery(con_dbOut, "SELECT MAX(scenario_id) FROM runs")) infer_runsN_total <- as.integer(dbGetQuery(con_dbOut, @@ -885,6 +883,12 @@ recreate_dbWork <- function(path, dbOutput, use_granular_control, infer_runIDmax_sites <- as.integer(dbGetQuery(con_dbOut, "SELECT MAX(site_id) FROM sites")) + # Extract information from dbOutput table 'experimental_labels' + infer_expN <- if (dbExistsTable(con_dbOut, "experimental_labels")) { + as.integer(dbGetQuery(con_dbOut, + "SELECT COUNT(*) FROM experimental_labels")) + } else 1 + #--- If dbWork exists, then copy timing information if design is current dbWork <- fname_dbWork(path) From 1c9555362744172ff1a45c814156767b3d3ba774 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Sun, 13 Oct 2019 16:39:59 -0400 Subject: [PATCH 11/21] Fix documentation for function `trewartha_climate` --- R/Miscellaneous_Functions.R | 4 ++-- man/rbind_2cols_nonoverlapping.Rd | 25 +++++++++++++++++++++++++ man/trewartha_climate.Rd | 30 ++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 man/rbind_2cols_nonoverlapping.Rd create mode 100644 man/trewartha_climate.Rd diff --git a/R/Miscellaneous_Functions.R b/R/Miscellaneous_Functions.R index 5e34d85e..8fe5ff67 100644 --- a/R/Miscellaneous_Functions.R +++ b/R/Miscellaneous_Functions.R @@ -462,7 +462,7 @@ calc_drylandindices <- function(annualPPT, annualPET, monthlyTemp, #' Main climate classification according to Trewartha #' #' The main climate classifications based on mean monthly temperature, i.e., -#' without group B--dry, include \describe{ +#' without group B--dry, include \itemize{ #' \item Group A (tropical): sum(months >= 18 C) == 12 #' \item Group C (subtropical): #' sum(months >= 10 C) >= 8 & sum(months >= 18 C) < 12 @@ -474,7 +474,7 @@ calc_drylandindices <- function(annualPPT, annualPET, monthlyTemp, #' @param meanTmonthly_C A numeric vector of length 12. Mean monthly air #' temperature in degree Celsius. #' -#' @seealso \code{\link[ClimClass](koeppen_geiger)} +#' @seealso \code{\link[ClimClass]{koeppen_geiger}} #' @references Trewartha, G.T. and Lyle, H.H., 1980: An Introduction to Climate. #' MacGraw - Hill, 5th Ed. Appendix: Koeppen's Classification of Climates trewartha_climate <- function(meanTmonthly_C) { diff --git a/man/rbind_2cols_nonoverlapping.Rd b/man/rbind_2cols_nonoverlapping.Rd new file mode 100644 index 00000000..0a0517a5 --- /dev/null +++ b/man/rbind_2cols_nonoverlapping.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/ExtractData_ClimateDownscaling.R +\name{rbind_2cols_nonoverlapping} +\alias{rbind_2cols_nonoverlapping} +\title{\code{rbind} two objects, but make sure that there is no duplication in two +indicator columns.} +\usage{ +rbind_2cols_nonoverlapping(x1, x2) +} +\arguments{ +\item{x1}{A two dimensional numeric object; the first two columns (e.g., +years, months) are matched up against \code{x2}.} + +\item{x2}{Same as \code{x1}.} +} +\value{ +The object that would result from \code{rbind(x1, x2)} but where + any duplication, as determined by the first two columns, is resolved, i.e., + copy with \code{NAs} is ignored or arithmetic mean across \code{x1} and + \code{x2}. +} +\description{ +\code{rbind} two objects, but make sure that there is no duplication in two +indicator columns. +} diff --git a/man/trewartha_climate.Rd b/man/trewartha_climate.Rd new file mode 100644 index 00000000..3f795c52 --- /dev/null +++ b/man/trewartha_climate.Rd @@ -0,0 +1,30 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/Miscellaneous_Functions.R +\name{trewartha_climate} +\alias{trewartha_climate} +\title{Main climate classification according to Trewartha} +\usage{ +trewartha_climate(meanTmonthly_C) +} +\arguments{ +\item{meanTmonthly_C}{A numeric vector of length 12. Mean monthly air +temperature in degree Celsius.} +} +\description{ +The main climate classifications based on mean monthly temperature, i.e., +without group B--dry, include \itemize{ + \item Group A (tropical): sum(months >= 18 C) == 12 + \item Group C (subtropical): + sum(months >= 10 C) >= 8 & sum(months >= 18 C) < 12 + \item Group D (temperate and continental): sum(months >= 10 C) %in% 4:7 + \item Group E (boreal): sum(months >= 10 C) %in% 1:3 + \item Group F (polar): sum(months >= 10 C) == 0 +} +} +\references{ +Trewartha, G.T. and Lyle, H.H., 1980: An Introduction to Climate. + MacGraw - Hill, 5th Ed. Appendix: Koeppen's Classification of Climates +} +\seealso{ +\code{\link[ClimClass]{koeppen_geiger}} +} From efa440f422a6fbdc7fbb871d98758edf16d02a7c Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Wed, 16 Oct 2019 08:49:11 -0400 Subject: [PATCH 12/21] Fix `do_OneSite`: setting years - if `start year` of a simulation run was later than the default end year, then the code was failing --> set `end year` before setting `start year` --- R/Simulation_Run.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/Simulation_Run.R b/R/Simulation_Run.R index 598451db..be820e19 100644 --- a/R/Simulation_Run.R +++ b/R/Simulation_Run.R @@ -376,8 +376,8 @@ do_OneSite <- function(i_sim, i_SWRunInformation, i_sw_input_soillayers, swRunScenariosData[[1]] <- swDefaultInputs #adjust simulation years - rSOILWAT2::swYears_StartYear(swRunScenariosData[[1]]) <- as.integer(isim_time[["simstartyr"]]) rSOILWAT2::swYears_EndYear(swRunScenariosData[[1]]) <- as.integer(isim_time[["endyr"]]) + rSOILWAT2::swYears_StartYear(swRunScenariosData[[1]]) <- as.integer(isim_time[["simstartyr"]]) #------2. Step: a) Information for this SOILWAT2-run from treatment SOILWAT2 input files stored in dir_in_treat if (any(create_treatments == "sw")) From 6a9583455c6d0c78348a719fff172d3b857c7fc3 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Wed, 16 Oct 2019 09:27:06 -0400 Subject: [PATCH 13/21] Fix aggregations `input_VegetationBiomassTrends` and `input_CO2Effects` - Problem: `get_Vegetation_yr` and `get_CO2effects_yr` fail with rSOILWAT2 v3.1.2 --> extract data from the new slots - close #368 --- R/Aggregation_Functions.R | 22 ++++++++++++++++------ R/Simulation_Run.R | 30 ++++++++++++++++++++---------- R/rSOILWAT2_DataAccess.R | 16 ++++++++++++---- 3 files changed, 48 insertions(+), 20 deletions(-) diff --git a/R/Aggregation_Functions.R b/R/Aggregation_Functions.R index c440f238..e1bff8f0 100644 --- a/R/Aggregation_Functions.R +++ b/R/Aggregation_Functions.R @@ -102,9 +102,15 @@ fields_input_VegetationBiomassTrends <- function(aon, ...) { # nolint id <- "input_VegetationBiomassTrends" if (isTRUE(aon[[id]])) { - vtemp <- c("Grass", "Shrub", "Tree", "Forb") - temp <- paste0(rep(c(vtemp, "Total"), 2), "_", - rep(c("Total", "Live"), each = 5), "Biomass_gPERm2_mean") + vtemp <- c("Tree", "Shrub", "Forb", "Grass") + temp <- paste0( + c(paste0( + rep(c("Total", vtemp), 2), "_", + rep(c("Total", "Live"), each = 1 + length(vtemp)) + ), + "Litter_" + ), + "Biomass_gPERm2_mean") } list(aon = id, N = length(temp), fields = list(coerce_sqlNames(temp))) @@ -211,9 +217,13 @@ fields_input_CO2Effects <- function(aon, ...) { # nolint id <- "input_CO2Effects" if (isTRUE(aon[[id]])) { - vtemp <- c("Grass", "Shrub", "Tree", "Forb") - temp <- paste0(rep(vtemp, 2), "_", - rep(c("Biomass", "WUE"), each = 4), "_CO2multiplier_fraction_mean") + vtemp <- c("Tree", "Shrub", "Forb", "Grass") + temp <- paste0( + rep(vtemp, 2), + "_", + rep(c("Biomass", "WUE"), each = 4), + "_CO2multiplier_fraction_mean" + ) } list(aon = id, N = length(temp), fields = list(coerce_sqlNames(temp))) diff --git a/R/Simulation_Run.R b/R/Simulation_Run.R index be820e19..142a3881 100644 --- a/R/Simulation_Run.R +++ b/R/Simulation_Run.R @@ -2021,15 +2021,21 @@ do_OneSite <- function(i_sim, i_SWRunInformation, i_sw_input_soillayers, if (isTRUE(prj_todos[["aon"]][["input_VegetationBiomassTrends"]])) { nv0 <- nv - print_debug(opt_verbosity, tag_simpidfid, "aggregating", "input_VegetationBiomassMonthly") + print_debug(opt_verbosity, tag_simpidfid, "aggregating", "input_VegetationBiomassTrends") - if (!exists("veg.yr")) veg.yr <- get_Vegetation_yr(runDataSC, isim_time) + if (!exists("veg.yr")) { + veg.yr <- get_Vegetation_yr(runDataSC, isim_time) + } - nv_add <- ncol(veg.yr[["val"]]) - nv_new <- nv + nv_add - resMeans[nv:(nv_new - 1)] <- .colMeans(veg.yr[["val"]], isim_time$no.useyr, nv_add) - resSDs[nv:(nv_new - 1)] <- apply(veg.yr[["val"]], 2, stats::sd) - nv <- nv_new + for (vcomp in c("totalbiomass", "livebiomass", "litter")) { + nv_add <- ncol(veg.yr[[vcomp]]) + nv_new <- nv + nv_add + resMeans[nv:(nv_new - 1)] <- .colMeans(veg.yr[[vcomp]], + m = isim_time$no.useyr, n = nv_add) + resSDs[nv:(nv_new - 1)] <- apply(veg.yr[[vcomp]], + MARGIN = 2, FUN = stats::sd) + nv <- nv_new + } print_debugN(opt_verbosity, tag_simpidfid, prj_todos, nv - nv0, "input_VegetationBiomassTrends") } @@ -2125,12 +2131,16 @@ do_OneSite <- function(i_sim, i_SWRunInformation, i_sw_input_soillayers, nv0 <- nv print_debug(opt_verbosity, tag_simpidfid, "aggregating", "input_CO2Effects") - if (!exists("co2effects.yr")) co2effects.yr <- get_CO2effects_yr(runDataSC, isim_time) + if (!exists("co2effects.yr")) { + co2effects.yr <- get_CO2effects_yr(runDataSC, isim_time) + } nv_add <- ncol(co2effects.yr[["val"]]) nv_new <- nv + nv_add - resMeans[nv:(nv_new - 1)] <- .colMeans(co2effects.yr[["val"]], isim_time$no.useyr, nv_add) - resSDs[nv:(nv_new - 1)] <- apply(co2effects.yr[["val"]], 2, stats::sd) + resMeans[nv:(nv_new - 1)] <- .colMeans(co2effects.yr[["val"]], + m = isim_time$no.useyr, n = nv_add) + resSDs[nv:(nv_new - 1)] <- apply(co2effects.yr[["val"]], + MARGIN = 2, FUN = stats::sd) nv <- nv_new print_debugN(opt_verbosity, tag_simpidfid, prj_todos, nv - nv0, "input_CO2Effects") diff --git a/R/rSOILWAT2_DataAccess.R b/R/rSOILWAT2_DataAccess.R index dfa63822..4dd176df 100644 --- a/R/rSOILWAT2_DataAccess.R +++ b/R/rSOILWAT2_DataAccess.R @@ -346,14 +346,22 @@ get_RunOnOff_yr <- function(x, st) { #' @inheritParams swOutput_access #' @rdname swOutput_access get_Vegetation_yr <- function(x, st) { - x <- slot(slot(x, "CO2EFFECTS"), "Year")[st$index.useyr, , drop = FALSE] - list(val = x[, 1 + seq_len(2 * 5), drop = FALSE]) + tmp <- slot(slot(x, "BIOMASS"), "Year")[st$index.useyr, , drop = FALSE] + ids <- seq_len(5L) + list( + cover = tmp[, 1L + ids, drop = FALSE], + litter = tmp[, 12L, drop = FALSE], + totalbiomass = tmp[, 6L + ids, drop = FALSE], + livebiomass = tmp[, 12L + ids, drop = FALSE] + ) } #' @inheritParams swOutput_access #' @rdname swOutput_access get_CO2effects_yr <- function(x, st) { - x <- slot(slot(x, "CO2EFFECTS"), "Year")[st$index.useyr, , drop = FALSE] - list(val = x[, 11 + seq_len(2 * 4), drop = FALSE]) + tmp <- slot(slot(x, "CO2EFFECTS"), "Year")[st$index.useyr, , drop = FALSE] + list( + val = tmp[, -1, drop = FALSE] + ) } From b779a30658cdbee1f3c65b24ae71d7eb9472b535 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Wed, 16 Oct 2019 12:58:58 -0400 Subject: [PATCH 14/21] Update test project reference database - commit 6a9583455c6d0c78348a719fff172d3b857c7fc3 changed output database --- .../0_ReferenceOutput/dbOutput_TestPrj4_v3.2.0.sqlite3 | 3 --- .../0_ReferenceOutput/dbOutput_TestPrj4_v4.1.0.sqlite3 | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) delete mode 100644 tests/test_data/0_ReferenceOutput/dbOutput_TestPrj4_v3.2.0.sqlite3 create mode 100644 tests/test_data/0_ReferenceOutput/dbOutput_TestPrj4_v4.1.0.sqlite3 diff --git a/tests/test_data/0_ReferenceOutput/dbOutput_TestPrj4_v3.2.0.sqlite3 b/tests/test_data/0_ReferenceOutput/dbOutput_TestPrj4_v3.2.0.sqlite3 deleted file mode 100644 index a602f44f..00000000 --- a/tests/test_data/0_ReferenceOutput/dbOutput_TestPrj4_v3.2.0.sqlite3 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4a377e562321b4990106a308334f8173655a3ed4c7ca383d37aa9e8ebc130460 -size 4980736 diff --git a/tests/test_data/0_ReferenceOutput/dbOutput_TestPrj4_v4.1.0.sqlite3 b/tests/test_data/0_ReferenceOutput/dbOutput_TestPrj4_v4.1.0.sqlite3 new file mode 100644 index 00000000..54d3484d --- /dev/null +++ b/tests/test_data/0_ReferenceOutput/dbOutput_TestPrj4_v4.1.0.sqlite3 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8ceb095c6901790fe1d9c6061d27eeeda7ffd84c9fb4ae09a839542414eb0857 +size 4980736 From 899248709c404e58d0059f6e31f978f9e4a2ff0e Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Wed, 16 Oct 2019 13:00:11 -0400 Subject: [PATCH 15/21] Upgrade to `lintr` package version 2.0.0 - de-active default new lintr `cyclocomp_linter` for now (consider activating it eventually) --- .Rbuildignore | 2 + .gitignore | 2 + .lintr | 35 +++-- DESCRIPTION | 6 +- R/Aggregation_Functions.R | 140 +++++++++--------- R/ExtractData_Elevation.R | 2 +- R/Miscellaneous_Functions.R | 6 +- R/OutputDatabase.R | 30 ++-- R/Parallel.R | 11 +- R/Simulation_Project.R | 10 +- R/Soils_Functions.R | 7 +- R/Spatial_Functions.R | 6 +- R/Testproject_Functions.R | 36 +++-- R/WeatherDB.R | 16 +- R/WeatherDB_Check.R | 3 +- R/WorkDatabase.R | 2 +- inst/WORDLIST | 3 + man/export_objects_to_workers.Rd | 2 +- man/gather_objects_for_export.Rd | 8 +- man/trewartha_climate.Rd | 2 +- .../testthat/test_OutputDatabase_DataAccess.R | 4 +- .../testthat/test_rSFSW2_CodeStylePractices.R | 28 +--- tests/testthat/test_rSFSW2_Spelling.R | 5 +- 23 files changed, 197 insertions(+), 169 deletions(-) diff --git a/.Rbuildignore b/.Rbuildignore index 77510c8a..cd61235a 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -14,3 +14,5 @@ ^cran-comments\.md$ ^NEWS\.md$ +^doc$ +^Meta$ diff --git a/.gitignore b/.gitignore index 97aa07da..4047fc4a 100644 --- a/.gitignore +++ b/.gitignore @@ -35,3 +35,5 @@ src/*.o src/*.so src/*.dll .Rproj.user +doc +Meta diff --git a/.lintr b/.lintr index fd18a8e4..eb18283d 100644 --- a/.lintr +++ b/.lintr @@ -1,21 +1,38 @@ linters: with_defaults( - #--- DEFAULT LINTERS - # Default line length: - line_length_linter(80L), + #------ DEFAULT LINTERS + assignment_linter, closed_curly_linter(allow_single_line = TRUE), - # Turn off default linters for now: + commas_linter, + commented_code_linter, + equals_na_linter, + function_left_parentheses_linter, + infix_spaces_linter, + line_length_linter(80L), + no_tab_linter, + object_length_linter, + object_usage_linter, + open_curly_linter, + paren_brace_linter, + pipe_continuation_linter, + seq_linter, + single_quotes_linter, + spaces_inside_linter, + spaces_left_parentheses_linter, + trailing_blank_lines_linter, + trailing_whitespace_linter, + #--- Turn off default linters for now: object_name_linter = NULL, - #--- NON-DEFAULT LINTERS - # Not activated non-default linters: + cyclocomp_linter = NULL, + #------ NON-DEFAULT LINTERS + #--- Not activated non-default linters: #extraction_operator_linter, #implicit_integer_linter, #todo_comment_linter, - # Activated non-default linters: - T_and_F_symbol_linter, + #--- Activated non-default linters: absolute_path_linter(lax = TRUE), + T_and_F_symbol_linter, nonportable_path_linter(lax = TRUE), semicolon_terminator_linter(semicolon = c("compound", "trailing")), - seq_linter, undesirable_function_linter, undesirable_operator_linter, unneeded_concatenation_linter) diff --git a/DESCRIPTION b/DESCRIPTION index 382001dc..589a8c41 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: rSFSW2 Title: Simulation Framework for SOILWAT2 -Version: 4.0.0 -Date: 2019-05-03 +Version: 4.1.0 +Date: 2019-10-16 Authors@R: c( person("Daniel", "Schlaepfer", email = "daniel.schlaepfer@yale.edu", comment = c(ORCID = "0000-0001-9973-2065"), role = c("aut", "cre")), @@ -45,7 +45,7 @@ Suggests: spelling (>= 1.1), hunspell (>= 2.9), covr, - lintr (>= 1.0.3.9000), + lintr (>= 2.0.0), goodpractice Remotes: github::dschlaep/weathergen diff --git a/R/Aggregation_Functions.R b/R/Aggregation_Functions.R index e1bff8f0..f53b1fb8 100644 --- a/R/Aggregation_Functions.R +++ b/R/Aggregation_Functions.R @@ -13,7 +13,7 @@ #' the number of output fields and \code{fields} contains a list with the #' names of those output fields. #' @export -generate_OverallAggregation_fields <- function(aon, opt_agg) { # nolint +generate_OverallAggregation_fields <- function(aon, opt_agg) { field_args <- list( aon = aon, opt_agg = opt_agg, @@ -53,7 +53,7 @@ coerce_sqlNames <- function(x) { #0. -fields_input_SoilProfile <- function(aon, ...) { # nolint +fields_input_SoilProfile <- function(aon, ...) { temp <- NULL id <- "input_SoilProfile" @@ -68,7 +68,7 @@ fields_input_SoilProfile <- function(aon, ...) { # nolint } #1. -fields_input_FractionVegetationComposition <- function(aon, ...) { # nolint +fields_input_FractionVegetationComposition <- function(aon, ...) { temp <- NULL id <- "input_FractionVegetationComposition" @@ -82,7 +82,7 @@ fields_input_FractionVegetationComposition <- function(aon, ...) { # nolint } #2b -fields_input_VegetationBiomassMonthly <- function(aon, ...) { # nolint +fields_input_VegetationBiomassMonthly <- function(aon, ...) { temp <- NULL id <- "input_VegetationBiomassMonthly" @@ -97,7 +97,7 @@ fields_input_VegetationBiomassMonthly <- function(aon, ...) { # nolint } #2b -fields_input_VegetationBiomassTrends <- function(aon, ...) { # nolint +fields_input_VegetationBiomassTrends <- function(aon, ...) { temp <- NULL id <- "input_VegetationBiomassTrends" @@ -117,7 +117,7 @@ fields_input_VegetationBiomassTrends <- function(aon, ...) { # nolint } #3. -fields_input_VegetationPeak <- function(aon, ...) { # nolint +fields_input_VegetationPeak <- function(aon, ...) { temp <- NULL id <- "input_VegetationPeak" @@ -130,7 +130,7 @@ fields_input_VegetationPeak <- function(aon, ...) { # nolint } #4. -fields_input_Phenology <- function(aon, ...) { # nolint +fields_input_Phenology <- function(aon, ...) { temp <- NULL id <- "input_Phenology" @@ -142,7 +142,7 @@ fields_input_Phenology <- function(aon, ...) { # nolint } #5. -fields_input_TranspirationCoeff <- function(aon, opt_agg, ...) { # nolint +fields_input_TranspirationCoeff <- function(aon, opt_agg, ...) { temp <- NULL id <- "input_TranspirationCoeff" @@ -197,7 +197,7 @@ fields_input_TranspirationCoeff <- function(aon, opt_agg, ...) { # nolint } #6. -fields_input_ClimatePerturbations <- function(aon, ...) { # nolint +fields_input_ClimatePerturbations <- function(aon, ...) { temp <- NULL id <- "input_ClimatePerturbations" @@ -212,7 +212,7 @@ fields_input_ClimatePerturbations <- function(aon, ...) { # nolint } #6b -fields_input_CO2Effects <- function(aon, ...) { # nolint +fields_input_CO2Effects <- function(aon, ...) { temp <- NULL id <- "input_CO2Effects" @@ -232,7 +232,7 @@ fields_input_CO2Effects <- function(aon, ...) { # nolint #------Aggregation: Climate and weather---################################### #7. -fields_yearlyTemp <- function(aon, ...) { # nolint +fields_yearlyTemp <- function(aon, ...) { temp <- NULL id <- "yearlyTemp" @@ -292,7 +292,7 @@ fields_dailySnowpack <- function(aon, opt_agg, ...) { } #11 -fields_dailyFrostInSnowfreePeriod <- function(aon, opt_agg, # nolint +fields_dailyFrostInSnowfreePeriod <- function(aon, opt_agg, fieldtag_Tmin_crit_C, ...) { temp <- NULL @@ -362,7 +362,7 @@ fields_dailyCoolDays <- function(aon, fieldtag_Tmean_crit_C, ...) { } #13 -fields_dailyPrecipitationEventSizeDistribution <- function(aon, opt_agg, ...) { # nolint +fields_dailyPrecipitationEventSizeDistribution <- function(aon, opt_agg, ...) { temp <- NULL id <- "dailyPrecipitationEventSizeDistribution" @@ -376,7 +376,7 @@ fields_dailyPrecipitationEventSizeDistribution <- function(aon, opt_agg, ...) { } #15 -fields_yearlyPET <- function(aon, ...) { # nolint +fields_yearlyPET <- function(aon, ...) { temp <- NULL id <- "yearlyPET" @@ -388,7 +388,7 @@ fields_yearlyPET <- function(aon, ...) { # nolint } #16 -fields_monthlySeasonalityIndices <- function(aon, ...) { # nolint +fields_monthlySeasonalityIndices <- function(aon, ...) { temp <- NULL id <- "monthlySeasonalityIndices" @@ -403,7 +403,7 @@ fields_monthlySeasonalityIndices <- function(aon, ...) { # nolint #---Aggregation: Climatic dryness #17 -fields_yearlymonthlyTemperateDrylandIndices <- function(aon, ...) { # nolint +fields_yearlymonthlyTemperateDrylandIndices <- function(aon, ...) { temp <- NULL id <- "yearlymonthlyTemperateDrylandIndices" @@ -417,7 +417,7 @@ fields_yearlymonthlyTemperateDrylandIndices <- function(aon, ...) { # nolint } #18 -fields_yearlyDryWetPeriods <- function(aon, ...) { # nolint +fields_yearlyDryWetPeriods <- function(aon, ...) { temp <- NULL id <- "yearlyDryWetPeriods" @@ -430,7 +430,7 @@ fields_yearlyDryWetPeriods <- function(aon, ...) { # nolint } #19 -fields_dailyWeatherGeneratorCharacteristics <- function(aon, ...) { # nolint +fields_dailyWeatherGeneratorCharacteristics <- function(aon, ...) { temp <- NULL id <- "dailyWeatherGeneratorCharacteristics" @@ -444,7 +444,7 @@ fields_dailyWeatherGeneratorCharacteristics <- function(aon, ...) { # nolint } #20 -fields_dailyPrecipitationFreeEventDistribution <- function(aon, opt_agg, ...) { # nolint +fields_dailyPrecipitationFreeEventDistribution <- function(aon, opt_agg, ...) { temp <- NULL id <- "dailyPrecipitationFreeEventDistribution" @@ -459,7 +459,7 @@ fields_dailyPrecipitationFreeEventDistribution <- function(aon, opt_agg, ...) { } #21 -fields_monthlySPEIEvents <- function(aon, ...) { # nolint +fields_monthlySPEIEvents <- function(aon, ...) { temp <- NULL id <- "monthlySPEIEvents" @@ -483,7 +483,7 @@ fields_monthlySPEIEvents <- function(aon, ...) { # nolint #---Aggregation: Climatic control #22 -fields_monthlyPlantGrowthControls <- function(aon, ...) { # nolint +fields_monthlyPlantGrowthControls <- function(aon, ...) { temp <- NULL id <- "monthlyPlantGrowthControls" @@ -496,7 +496,7 @@ fields_monthlyPlantGrowthControls <- function(aon, ...) { # nolint } #23 -fields_dailyC4_TempVar <- function(aon, ...) { # nolint +fields_dailyC4_TempVar <- function(aon, ...) { temp <- NULL id <- "dailyC4_TempVar" @@ -539,7 +539,7 @@ fields_dailyColdDegreeDays <- function(aon, opt_agg, ...) { #------Aggregation: Yearly water balance---################################## #27.0 -fields_yearlyAET <- function(aon, ...) { # nolint +fields_yearlyAET <- function(aon, ...) { temp <- NULL id <- "yearlyAET" @@ -551,7 +551,7 @@ fields_yearlyAET <- function(aon, ...) { # nolint } #27 -fields_yearlyWaterBalanceFluxes <- function(aon, ...) { # nolint +fields_yearlyWaterBalanceFluxes <- function(aon, ...) { temp <- NULL id <- "yearlyWaterBalanceFluxes" @@ -575,7 +575,7 @@ fields_yearlyWaterBalanceFluxes <- function(aon, ...) { # nolint } #27.1 -fields_yearlyTranspirationBySoilLayer <- function(aon, ...) { # nolint +fields_yearlyTranspirationBySoilLayer <- function(aon, ...) { temp <- NULL id <- "yearlyTranspirationBySoilLayer" @@ -591,7 +591,7 @@ fields_yearlyTranspirationBySoilLayer <- function(aon, ...) { # nolint } #27.2 -fields_dailySoilWaterPulseVsStorage <- function(aon, ...) { # nolint +fields_dailySoilWaterPulseVsStorage <- function(aon, ...) { temp <- NULL id <- "dailySoilWaterPulseVsStorage" @@ -607,7 +607,7 @@ fields_dailySoilWaterPulseVsStorage <- function(aon, ...) { # nolint #------Aggregation: Daily extreme values---################################## #28 -fields_dailyTranspirationExtremes <- function(aon, ...) { # nolint +fields_dailyTranspirationExtremes <- function(aon, ...) { temp <- NULL id <- "dailyTranspirationExtremes" @@ -620,7 +620,7 @@ fields_dailyTranspirationExtremes <- function(aon, ...) { # nolint } #29 -fields_dailyTotalEvaporationExtremes <- function(aon, ...) { # nolint +fields_dailyTotalEvaporationExtremes <- function(aon, ...) { temp <- NULL id <- "dailyTotalEvaporationExtremes" @@ -634,7 +634,7 @@ fields_dailyTotalEvaporationExtremes <- function(aon, ...) { # nolint } #30 -fields_dailyDrainageExtremes <- function(aon, ...) { # nolint +fields_dailyDrainageExtremes <- function(aon, ...) { temp <- NULL id <- "dailyDrainageExtremes" @@ -647,7 +647,7 @@ fields_dailyDrainageExtremes <- function(aon, ...) { # nolint } #31 -fields_dailyInfiltrationExtremes <- function(aon, ...) { # nolint +fields_dailyInfiltrationExtremes <- function(aon, ...) { temp <- NULL id <- "dailyInfiltrationExtremes" @@ -660,7 +660,7 @@ fields_dailyInfiltrationExtremes <- function(aon, ...) { # nolint } #32 -fields_dailyAETExtremes <- function(aon, ...) { # nolint +fields_dailyAETExtremes <- function(aon, ...) { temp <- NULL id <- "dailyAETExtremes" @@ -673,7 +673,7 @@ fields_dailyAETExtremes <- function(aon, ...) { # nolint } #33 -fields_dailySWPextremes <- function(aon, ...) { # nolint +fields_dailySWPextremes <- function(aon, ...) { temp <- NULL id <- "dailySWPextremes" @@ -688,7 +688,7 @@ fields_dailySWPextremes <- function(aon, ...) { # nolint } #34 -fields_dailyRechargeExtremes <- function(aon, ...) { # nolint +fields_dailyRechargeExtremes <- function(aon, ...) { temp <- NULL id <- "dailyRechargeExtremes" @@ -714,8 +714,8 @@ fields_dailyRechargeExtremes <- function(aon, ...) { # nolint #' \item ACS = AnhydrousControlSection #' \item consec = consecutive #' } -fields_dailyNRCS_SoilMoistureTemperatureRegimes_Intermediates <- function(aon, # nolint - ...) { +fields_dailyNRCS_SoilMoistureTemperatureRegimes_Intermediates <- + function(aon, ...) { temp <- NULL id <- "dailyNRCS_SoilMoistureTemperatureRegimes_Intermediates" @@ -784,7 +784,7 @@ fields_dailyNRCS_SoilMoistureTemperatureRegimes_Intermediates <- function(aon, #' @seealso #' \code{\link{fields_dailyNRCS_SoilMoistureTemperatureRegimes_Intermediates}} -fields_dailyNRCS_SoilMoistureTemperatureRegimes <- function(aon, ...) { # nolint +fields_dailyNRCS_SoilMoistureTemperatureRegimes <- function(aon, ...) { temp <- NULL id <- "dailyNRCS_SoilMoistureTemperatureRegimes" @@ -799,7 +799,7 @@ fields_dailyNRCS_SoilMoistureTemperatureRegimes <- function(aon, ...) { # nolint } #35b -fields_dailyNRCS_Chambers2014_ResilienceResistance <- function(aon, ...) { # nolint +fields_dailyNRCS_Chambers2014_ResilienceResistance <- function(aon, ...) { temp <- NULL id <- "dailyNRCS_Chambers2014_ResilienceResistance" @@ -813,7 +813,7 @@ fields_dailyNRCS_Chambers2014_ResilienceResistance <- function(aon, ...) { # nol } #35c -fields_dailyNRCS_Maestas2016_ResilienceResistance <- function(aon, ...) { # nolint +fields_dailyNRCS_Maestas2016_ResilienceResistance <- function(aon, ...) { temp <- NULL id <- "dailyNRCS_Maestas2016_ResilienceResistance" @@ -840,7 +840,7 @@ fields_dailyWetDegreeDays <- function(aon, opt_agg, fieldtag_SWPcrit_MPa, ...) { } #35.3 -fields_dailyThermalDrynessStartEnd <- function(aon, fieldtag_SWPcrit_MPa, ...) { # nolint +fields_dailyThermalDrynessStartEnd <- function(aon, fieldtag_SWPcrit_MPa, ...) { temp <- NULL id <- "dailyThermalDrynessStartEnd" @@ -855,7 +855,7 @@ fields_dailyThermalDrynessStartEnd <- function(aon, fieldtag_SWPcrit_MPa, ...) { } #35.4 -fields_dailyThermalSWPConditionCount <- function(aon, opt_agg, # nolint +fields_dailyThermalSWPConditionCount <- function(aon, opt_agg, fieldtag_SWPcrit_MPa, fieldtag_Tmean_crit_C, ...) { temp <- NULL @@ -895,7 +895,7 @@ fields_monthlySWPdryness <- function(aon, opt_agg, fieldtag_SWPcrit_MPa, ...) { } #37 -fields_dailySWPdrynessANDwetness <- function(aon, fieldtag_SWPcrit_MPa, ...) { # nolint +fields_dailySWPdrynessANDwetness <- function(aon, fieldtag_SWPcrit_MPa, ...) { temp <- NULL id <- "dailySWPdrynessANDwetness" @@ -918,7 +918,7 @@ fields_dailySWPdrynessANDwetness <- function(aon, fieldtag_SWPcrit_MPa, ...) { } #38 -fields_dailySuitablePeriodsDuration <- function(aon, opt_agg, # nolint +fields_dailySuitablePeriodsDuration <- function(aon, opt_agg, fieldtag_SWPcrit_MPa, ...) { temp <- NULL @@ -937,7 +937,7 @@ fields_dailySuitablePeriodsDuration <- function(aon, opt_agg, # nolint } #39 -fields_dailySuitablePeriodsAvailableWater <- function(aon, opt_agg, # nolint +fields_dailySuitablePeriodsAvailableWater <- function(aon, opt_agg, fieldtag_SWPcrit_MPa, ...) { temp <- NULL @@ -954,7 +954,7 @@ fields_dailySuitablePeriodsAvailableWater <- function(aon, opt_agg, # nolint } #40 -fields_dailySuitablePeriodsDrySpells <- function(aon, opt_agg, # nolint +fields_dailySuitablePeriodsDrySpells <- function(aon, opt_agg, fieldtag_SWPcrit_MPa, ...) { temp <- NULL @@ -975,7 +975,7 @@ fields_dailySuitablePeriodsDrySpells <- function(aon, opt_agg, # nolint } #41 -fields_dailySWPdrynessDurationDistribution <- function(aon, opt_agg, # nolint +fields_dailySWPdrynessDurationDistribution <- function(aon, opt_agg, fieldtag_SWPcrit_MPa, ...) { temp <- NULL @@ -1000,7 +1000,7 @@ fields_dailySWPdrynessDurationDistribution <- function(aon, opt_agg, # nolint } #42 -fields_dailySWPdrynessEventSizeDistribution <- function(aon, # nolint +fields_dailySWPdrynessEventSizeDistribution <- function(aon, fieldtag_SWPcrit_MPa, ...) { temp <- NULL @@ -1024,7 +1024,7 @@ fields_dailySWPdrynessEventSizeDistribution <- function(aon, # nolint } #43 -fields_dailySWPdrynessIntensity <- function(aon, fieldtag_SWPcrit_MPa, ...) { # nolint +fields_dailySWPdrynessIntensity <- function(aon, fieldtag_SWPcrit_MPa, ...) { temp <- NULL id <- "dailySWPdrynessIntensity" @@ -1041,7 +1041,7 @@ fields_dailySWPdrynessIntensity <- function(aon, fieldtag_SWPcrit_MPa, ...) { # } #43.2 -fields_dailyThermalDrynessStress <- function(aon, opt_agg, # nolint +fields_dailyThermalDrynessStress <- function(aon, opt_agg, fieldtag_SWPcrit_MPa, ...) { temp <- NULL @@ -1069,7 +1069,7 @@ fields_dailyThermalDrynessStress <- function(aon, opt_agg, # nolint } #43.3 -fields_periodicVWCmatricFirstLayer <- function(aon, opt_agg, ...) { # nolint +fields_periodicVWCmatricFirstLayer <- function(aon, opt_agg, ...) { temp <- NULL id <- "periodicVWCmatricFirstLayer" @@ -1095,7 +1095,7 @@ fields_periodicVWCmatricFirstLayer <- function(aon, opt_agg, ...) { # nolint #------Aggregation: Mean monthly values---################################### #44 -fields_monthlyTemp <- function(aon, ...) { # nolint +fields_monthlyTemp <- function(aon, ...) { temp <- NULL id <- "monthlyTemp" @@ -1107,7 +1107,7 @@ fields_monthlyTemp <- function(aon, ...) { # nolint } #45 -fields_monthlyPPT <- function(aon, ...) { # nolint +fields_monthlyPPT <- function(aon, ...) { temp <- NULL id <- "monthlyPPT" @@ -1119,7 +1119,7 @@ fields_monthlyPPT <- function(aon, ...) { # nolint } #46 -fields_monthlySnowpack <- function(aon, ...) { # nolint +fields_monthlySnowpack <- function(aon, ...) { temp <- NULL id <- "monthlySnowpack" @@ -1131,7 +1131,7 @@ fields_monthlySnowpack <- function(aon, ...) { # nolint } #47 -fields_monthlySoilTemp <- function(aon, ...) { # nolint +fields_monthlySoilTemp <- function(aon, ...) { temp <- NULL id <- "monthlySoilTemp" @@ -1145,7 +1145,7 @@ fields_monthlySoilTemp <- function(aon, ...) { # nolint } #48 -fields_monthlyRunoff <- function(aon, ...) { # nolint +fields_monthlyRunoff <- function(aon, ...) { temp <- NULL id <- "monthlyRunoff" @@ -1156,7 +1156,7 @@ fields_monthlyRunoff <- function(aon, ...) { # nolint list(aon = id, N = length(temp), fields = list(coerce_sqlNames(temp))) } -fields_monthlyRunon <- function(aon, ...) { # nolint +fields_monthlyRunon <- function(aon, ...) { temp <- NULL id <- "monthlyRunon" @@ -1168,7 +1168,7 @@ fields_monthlyRunon <- function(aon, ...) { # nolint } #49 -fields_monthlyHydraulicRedistribution <- function(aon, ...) { # nolint +fields_monthlyHydraulicRedistribution <- function(aon, ...) { temp <- NULL id <- "monthlyHydraulicRedistribution" @@ -1182,7 +1182,7 @@ fields_monthlyHydraulicRedistribution <- function(aon, ...) { # nolint } #50 -fields_monthlyInfiltration <- function(aon, ...) { # nolint +fields_monthlyInfiltration <- function(aon, ...) { temp <- NULL id <- "monthlyInfiltration" @@ -1194,7 +1194,7 @@ fields_monthlyInfiltration <- function(aon, ...) { # nolint } #51 -fields_monthlyDeepDrainage <- function(aon, ...) { # nolint +fields_monthlyDeepDrainage <- function(aon, ...) { temp <- NULL id <- "monthlyDeepDrainage" @@ -1206,7 +1206,7 @@ fields_monthlyDeepDrainage <- function(aon, ...) { # nolint } #52 -fields_monthlySWPmatric <- function(aon, ...) { # nolint +fields_monthlySWPmatric <- function(aon, ...) { temp <- NULL id <- "monthlySWPmatric" @@ -1220,7 +1220,7 @@ fields_monthlySWPmatric <- function(aon, ...) { # nolint } #53 a.) -fields_monthlyVWCbulk <- function(aon, ...) { # nolint +fields_monthlyVWCbulk <- function(aon, ...) { temp <- NULL id <- "monthlyVWCbulk" @@ -1234,7 +1234,7 @@ fields_monthlyVWCbulk <- function(aon, ...) { # nolint } #53 b.) -fields_monthlyVWCmatric <- function(aon, ...) { # nolint +fields_monthlyVWCmatric <- function(aon, ...) { temp <- NULL id <- "monthlyVWCmatric" @@ -1248,7 +1248,7 @@ fields_monthlyVWCmatric <- function(aon, ...) { # nolint } #54 -fields_monthlySWCbulk <- function(aon, ...) { # nolint +fields_monthlySWCbulk <- function(aon, ...) { temp <- NULL id <- "monthlySWCbulk" @@ -1278,7 +1278,7 @@ fields_monthlySWAbulk <- function(aon, fieldtag_SWPcrit_MPa, ...) { } #56 -fields_monthlyTranspiration <- function(aon, ...) { # nolint +fields_monthlyTranspiration <- function(aon, ...) { temp <- NULL id <- "monthlyTranspiration" @@ -1292,7 +1292,7 @@ fields_monthlyTranspiration <- function(aon, ...) { # nolint } #57 -fields_monthlySoilEvaporation <- function(aon, ...) { # nolint +fields_monthlySoilEvaporation <- function(aon, ...) { temp <- NULL id <- "monthlySoilEvaporation" @@ -1304,7 +1304,7 @@ fields_monthlySoilEvaporation <- function(aon, ...) { # nolint } #58 -fields_monthlyAET <- function(aon, ...) { # nolint +fields_monthlyAET <- function(aon, ...) { temp <- NULL id <- "monthlyAET" @@ -1316,7 +1316,7 @@ fields_monthlyAET <- function(aon, ...) { # nolint } #59 -fields_monthlyPET <- function(aon, ...) { # nolint +fields_monthlyPET <- function(aon, ...) { temp <- NULL id <- "monthlyPET" @@ -1328,7 +1328,7 @@ fields_monthlyPET <- function(aon, ...) { # nolint } #59.2 -fields_monthlyVPD <- function(aon, ...) { # nolint +fields_monthlyVPD <- function(aon, ...) { temp <- NULL id <- "monthlyVPD" @@ -1340,7 +1340,7 @@ fields_monthlyVPD <- function(aon, ...) { # nolint } #60 -fields_monthlyAETratios <- function(aon, ...) { # nolint +fields_monthlyAETratios <- function(aon, ...) { temp <- NULL id <- "monthlyAETratios" @@ -1353,7 +1353,7 @@ fields_monthlyAETratios <- function(aon, ...) { # nolint } #61 -fields_monthlyPETratios <- function(aon, ...) { # nolint +fields_monthlyPETratios <- function(aon, ...) { temp <- NULL id <- "monthlyPETratios" @@ -1368,7 +1368,7 @@ fields_monthlyPETratios <- function(aon, ...) { # nolint #------Aggregation: Potential regeneration---################################ #62 -fields_dailyRegeneration_bySWPSnow <- function(aon, ...) { # nolint +fields_dailyRegeneration_bySWPSnow <- function(aon, ...) { temp <- NULL id <- "dailyRegeneration_bySWPSnow" diff --git a/R/ExtractData_Elevation.R b/R/ExtractData_Elevation.R index 7e68f87d..715006be 100644 --- a/R/ExtractData_Elevation.R +++ b/R/ExtractData_Elevation.R @@ -137,7 +137,7 @@ do_ExtractElevation_NED_USA <- function(MMC, sim_size, sim_space, dir_ex_dem, #' @references Harmonized World Soil Database -do_ExtractElevation_HWSD_Global <- function(MMC, sim_size, sim_space, # nolint +do_ExtractElevation_HWSD_Global <- function(MMC, sim_size, sim_space, dir_ex_dem, fnames_in, resume, verbose) { if (verbose) { diff --git a/R/Miscellaneous_Functions.R b/R/Miscellaneous_Functions.R index 8fe5ff67..cc9a832a 100644 --- a/R/Miscellaneous_Functions.R +++ b/R/Miscellaneous_Functions.R @@ -132,7 +132,7 @@ set_options_warn_error <- function(debug.warn.level = 1L, #' #' @export enable_debug_dump <- function(dir_out = ".", file_tag = "debug") { - { # nolint + { op_prev <- options("warn") options(warn = 0) env_tosave <- new.env() @@ -149,7 +149,7 @@ enable_debug_dump <- function(dir_out = ".", file_tag = "debug") { file = file.path(dir_out, paste0("last.dump.", as.character(file_tag), ".RData"))) options(op_prev) - } # nolint + } } #' Remove one of possibly several expressions recorded by \code{on.exit} @@ -476,7 +476,7 @@ calc_drylandindices <- function(annualPPT, annualPET, monthlyTemp, #' #' @seealso \code{\link[ClimClass]{koeppen_geiger}} #' @references Trewartha, G.T. and Lyle, H.H., 1980: An Introduction to Climate. -#' MacGraw - Hill, 5th Ed. Appendix: Koeppen's Classification of Climates +#' McGraw - Hill, 5th Ed. Appendix: Koeppen's Classification of Climates trewartha_climate <- function(meanTmonthly_C) { stopifnot(length(meanTmonthly_C) == 12) diff --git a/R/OutputDatabase.R b/R/OutputDatabase.R index b3141015..fa4d1c13 100644 --- a/R/OutputDatabase.R +++ b/R/OutputDatabase.R @@ -125,7 +125,7 @@ dbOutput_ListOutputTables <- function(con = NULL, dbname = NULL) { #' that a table has records by soil layers. #' #' @export -dbOutput_Tables_have_SoilLayers <- function(tables = NULL, con = NULL, # nolint +dbOutput_Tables_have_SoilLayers <- function(tables = NULL, con = NULL, dbname = NULL) { use_con <- !is.null(con) && inherits(con, "SQLiteConnection") && @@ -262,7 +262,7 @@ get_fieldnames <- function(responseName, fields.header, fields.iTable) { #' Get data of variables in the overall aggregation table for one of the #' scenarios #' @export -get.SeveralOverallVariables_Scenario_old <- function(fdbrSFSW2, responseName, # nolint +get.SeveralOverallVariables_Scenario_old <- function(fdbrSFSW2, responseName, MeanOrSD = "Mean", scenario = "Current", whereClause = NULL) { dat <- NULL @@ -315,7 +315,7 @@ get.SeveralOverallVariables_Scenario_old <- function(fdbrSFSW2, responseName, # #' Get data of variables in the overall aggregation table for one of the #' scenarios #' @export -get.SeveralOverallVariables_Scenario <- function(fdbrSFSW2, responseName, # nolint +get.SeveralOverallVariables_Scenario <- function(fdbrSFSW2, responseName, MeanOrSD = "Mean", scenario = "Current", whereClause = NULL) { .Deprecated("dbOut_read_variables_from_scenario") @@ -464,7 +464,7 @@ dbOut_read_variables_from_scenario <- function(fname_dbOut, variables = NULL, #' Get data of variables in the overall aggregation table for one of the #' ensembles #' @export -get.SeveralOverallVariables_Ensemble <- function(fdbrSFSW2, fdbrSFSW2ens, # nolint +get.SeveralOverallVariables_Ensemble <- function(fdbrSFSW2, fdbrSFSW2ens, responseName, MeanOrSD = "Mean", fam, level, whereClause = NULL) { dat <- NULL @@ -1385,7 +1385,7 @@ move_temporary_to_outputDB <- function(SFSW2_prj_meta, t_job_start, #' \file{SQL_tmptxt_repeats.txt}.} #' #' @rdname move_temporary_to_outputDB -move_temporary_to_outputDB_withChecks <- function(SFSW2_prj_meta, t_job_start, # nolint +move_temporary_to_outputDB_withChecks <- function(SFSW2_prj_meta, t_job_start, opt_parallel, opt_behave, opt_out_run, opt_verbosity, chunk_size = 1000L, check_if_Pid_present = TRUE, dir_out_temp = NULL) { @@ -1545,7 +1545,7 @@ move_temporary_to_outputDB_withChecks <- function(SFSW2_prj_meta, t_job_start, # ids <- OKs[[tg]][["hasSL"]] sl <- OK_ndefault stop("I don't know variable 'dat' in: ", - 'sl[ids] <- as.integer(dat[["val"]][, 2L])') # nolint + 'sl[ids] <- as.integer(dat[["val"]][, 2L])') OKs[[tg]][["hasSL"]][ids] <- OK_line[ids] & is.finite(sl[ids]) ids <- OKs[[tg]][["hasSL"]] @@ -1674,7 +1674,7 @@ move_temporary_to_outputDB_withChecks <- function(SFSW2_prj_meta, t_job_start, # -do_copyCurrentConditionsFromDatabase <- function(dbOutput, dbOutput_current, # nolint +do_copyCurrentConditionsFromDatabase <- function(dbOutput, dbOutput_current, verbose = FALSE) { if (verbose) @@ -1990,8 +1990,8 @@ dbOutput_create_Design <- function(con_dbOut, SFSW2_prj_meta, if (any(!is.na(SFSW2_prj_inputs[["SWRunInformation"]]$WeatherFolder))) { # enforce that NA appears as a string instead of a logical runSWFolder <- SFSW2_prj_inputs[["SWRunInformation"]]$WeatherFolder - for (id_index in seq(runSWFolder)){ - if (is.na(runSWFolder[id_index])){ + for (id_index in seq(runSWFolder)) { + if (is.na(runSWFolder[id_index])) { SFSW2_prj_inputs[["SWRunInformation"]]$WeatherFolder[id_index] <- "NA" } } @@ -2020,8 +2020,8 @@ dbOutput_create_Design <- function(con_dbOut, SFSW2_prj_meta, stringsAsFactors = FALSE) # enforce that NA appears as a string instead of a logical - for (i in seq(sites_data$WeatherFolder)){ - if (is.na(sites_data$WeatherFolder[i])){ + for (i in seq(sites_data$WeatherFolder)) { + if (is.na(sites_data$WeatherFolder[i])) { sites_data$WeatherFolder[i] <- "NA" } } @@ -2353,7 +2353,7 @@ dbOutput_create_Design <- function(con_dbOut, SFSW2_prj_meta, #Get experimental_label_id db_combined_exp_treatments[irows, "experimental_id"] <- irows2 #insert all of the rows from experimentals - db_combined_exp_treatments[irows, SFSW2_prj_inputs[["create_experimentals"]]] <- db_experimentals[irows2, ] + db_combined_exp_treatments[irows, SFSW2_prj_inputs[["create_experimentals"]]] <- db_experimentals[irows2, ] #nolint } } } else { @@ -2626,7 +2626,7 @@ dbOutput_create_Design <- function(con_dbOut, SFSW2_prj_meta, invisible(NULL) } -dbOutput_create_OverallAggregationTable <- function(con_dbOut, fields) { # nolint +dbOutput_create_OverallAggregationTable <- function(con_dbOut, fields) { ncol_dbOut_overall <- sum(fields[, "N"]) @@ -2651,7 +2651,7 @@ dbOutput_create_OverallAggregationTable <- function(con_dbOut, fields) { # nolin sdString = sdString) } -dbOutput_create_DailyAggregationTable <- function(con_dbOut, req_aggs) { # nolint +dbOutput_create_DailyAggregationTable <- function(con_dbOut, req_aggs) { dailySQL <- dailyLayersSQL <- NULL if (req_aggs[["N"]] > 0) { @@ -3025,7 +3025,7 @@ make_dbTempOut <- function(dbOutput, dir_out_temp, fields, adaily, #' @param verbose A logical value. #' #' @export -dbOutput_update_OverallAggregationTable <- function(SFSW2_prj_meta, # nolint +dbOutput_update_OverallAggregationTable <- function(SFSW2_prj_meta, col_ids = NULL, chunksize = 1000, verbose = FALSE) { con_dbOut <- dbConnect(SQLite(), diff --git a/R/Parallel.R b/R/Parallel.R index a1636a33..5bfaa7a6 100644 --- a/R/Parallel.R +++ b/R/Parallel.R @@ -1,7 +1,10 @@ -#' Export R objects to MPI/socket workers +# nolint start +#' Export \var{R} objects to \var{MPI} or socket workers +# nolint end +#' +#' @param varlist A vector of R object names to export. +#' @param list_envs A list of environments in which to search for the R objects. #' -#' @param varlist A vector of R object names to export -#' @param list_envs A list of environments in which to search for the R objects #' @export gather_objects_for_export <- function(varlist, list_envs) { #---Determine environments @@ -36,7 +39,7 @@ do_import_objects <- function(obj_env) { #' Export objects to workers #' #' @param obj_env An environment containing R objects to export. -#' @param parallel_backend A character vector, either \var{\dQuote{mpi}}' or +#' @param parallel_backend A character vector, either \var{\dQuote{mpi}} or #' \var{\dQuote{socket}} #' @param cl A parallel (socket) cluster object #' diff --git a/R/Simulation_Project.R b/R/Simulation_Project.R index ab653c7d..61a8d3b7 100644 --- a/R/Simulation_Project.R +++ b/R/Simulation_Project.R @@ -11,7 +11,7 @@ #' in \file{R/sysdata.rda} and which is generated by package developers with #' the script \file{data-raw/prepare_default_project_infrastructure.R}. #' @export -setup_rSFSW2_project_infrastructure <- function(dir_prj, verbose = TRUE, # nolint +setup_rSFSW2_project_infrastructure <- function(dir_prj, verbose = TRUE, print.debug = FALSE) { masterinput_pattern <- "_InputMaster_" @@ -486,7 +486,7 @@ gather_project_inputs <- function(SFSW2_prj_meta, use_preprocin = TRUE, #' Populate \pkg{rSFSW2} project with input data #' @export -populate_rSFSW2_project_with_data <- function(SFSW2_prj_meta, opt_behave, # nolint +populate_rSFSW2_project_with_data <- function(SFSW2_prj_meta, opt_behave, opt_parallel, opt_chunks, opt_out_run, opt_verbosity) { if (opt_verbosity[["verbose"]]) { @@ -916,7 +916,7 @@ populate_rSFSW2_project_with_data <- function(SFSW2_prj_meta, opt_behave, # noli #' Attempt to check input data of a \pkg{rSFSW2} project for consistency #' @export -check_rSFSW2_project_input_data <- function(SFSW2_prj_meta, SFSW2_prj_inputs, # nolint +check_rSFSW2_project_input_data <- function(SFSW2_prj_meta, SFSW2_prj_inputs, opt_chunks, opt_verbosity) { if (opt_verbosity[["verbose"]]) { @@ -1337,8 +1337,8 @@ simulate_SOILWAT2_experiment <- function(SFSW2_prj_meta, SFSW2_prj_inputs, on.exit(dbWork_clean(SFSW2_prj_meta[["project_paths"]][["dir_out"]]), add = TRUE) - swof <- rSOILWAT2::sw_out_flags() # nolint - swDefaultInputs <- read_SOILWAT2_DefaultInputs() # nolint + swof <- rSOILWAT2::sw_out_flags() + swDefaultInputs <- read_SOILWAT2_DefaultInputs() args_do_OneSite <- gather_args_do_OneSite(SFSW2_prj_meta, SFSW2_prj_inputs) runs.completed <- run_simulation_experiment( diff --git a/R/Soils_Functions.R b/R/Soils_Functions.R index 19d7860a..6c3107fe 100644 --- a/R/Soils_Functions.R +++ b/R/Soils_Functions.R @@ -1,7 +1,8 @@ - +# nolint start getLayersWidth <- rSOILWAT2:::getLayersWidth calc_weights_from_depths <- rSOILWAT2:::calc_weights_from_depths add_layer_to_soil <- rSOILWAT2:::add_layer_to_soil +# nolint end #' The wrapper only handles 1-cm resolution of soil depths #' (mainly because of the \var{trco}) @@ -118,8 +119,8 @@ assign_aggregation_soillayers <- function(layers_depth, daily_lyr_agg) { init_soiltemperature <- function(layers_depth, lower.Tdepth, soilTupper, soilTlower) { - sl <- c(0, lower.Tdepth) # nolint - st <- c(soilTupper, soilTlower) # nolint + sl <- c(0, lower.Tdepth) + st <- c(soilTupper, soilTlower) stats::predict(stats::lm(st ~ sl), data.frame(sl = layers_depth)) } diff --git a/R/Spatial_Functions.R b/R/Spatial_Functions.R index b55fb8a7..1130b5e6 100644 --- a/R/Spatial_Functions.R +++ b/R/Spatial_Functions.R @@ -57,7 +57,7 @@ setGeneric("extract_rSFSW2", function(x, y, type, ...) #' @return A matrix with rows corresponding to the \code{!NA} cells of \code{y} #' and columns to layers of \code{x}. #' @export -extract_SFSW2_cells_from_raster <- function(x, y, ...) { # nolint +extract_SFSW2_cells_from_raster <- function(x, y, ...) { stopifnot(inherits(x, "Raster")) @@ -411,7 +411,7 @@ extract_blocks <- function(x, y, weights = FALSE) { vals } -extract2_Raster_SpatialPolygons <- function(x, ...) { # nolint +extract2_Raster_SpatialPolygons <- function(x, ...) { stop("Function 'extract2_Raster_SpatialPolygons' is not defined") } @@ -621,7 +621,7 @@ weighted.agg <- function(reagg, probs = NA) { #' @return A vector or matrix with length/rows corresponding to the \code{!NA} #' cells of \code{x} and columns to layers of \code{data}. #' @export -extract_from_external_raster_old <- function(x, data, ...) { # nolint +extract_from_external_raster_old <- function(x, data, ...) { .Deprecated(new = "extract_rSFSW2") diff --git a/R/Testproject_Functions.R b/R/Testproject_Functions.R index b54b96dd..eb8637bc 100644 --- a/R/Testproject_Functions.R +++ b/R/Testproject_Functions.R @@ -391,7 +391,7 @@ check_aggregated_output <- function(x) { #--- Water balance checks # (1) AET <= PET - temp <- with(x, all(AET_mm_mean <= PET_mm_mean)) # nolint + temp <- all(x[, "AET_mm_mean"] <= x[, "PET_mm_mean"]) if (!isTRUE(temp)) { temp <- list("(1) AET <= PET" = temp) @@ -402,8 +402,10 @@ check_aggregated_output <- function(x) { # (2) AET == E(total) + T(total) - temp <- with(x, all.equal(AET_mm_mean, Transpiration_Total_mm_mean + - Evaporation_Total_mm_mean)) + temp <- all.equal( + x[, "AET_mm_mean"], + x[, "Transpiration_Total_mm_mean"] + x[, "Evaporation_Total_mm_mean"] + ) if (!isTRUE(temp)) { temp <- list("AET == Ttotal + Etotal" = temp) @@ -414,8 +416,11 @@ check_aggregated_output <- function(x) { # (3) T(total) = sum of T(veg-type i from soil layer j) - temp <- with(x, all.equal(Transpiration_Total_mm_mean, - Transpiration_topLayers_mm_mean + Transpiration_bottomLayers_mm_mean)) + temp <- all.equal( + x[, "Transpiration_Total_mm_mean"], + x[, "Transpiration_topLayers_mm_mean"] + + x[, "Transpiration_bottomLayers_mm_mean"] + ) if (!isTRUE(temp)) { temp <- list("Total == sum of T(veg-type i from soil layer j)" = temp) @@ -428,10 +433,14 @@ check_aggregated_output <- function(x) { # (4) E(total) = E(total bare-soil) + E(ponded water) + # + E(total litter-intercepted) + # + E(total veg-intercepted) + E(snow sublimation) - temp <- with(x, all.equal(Evaporation_Total_mm_mean, - Evaporation_Soil_Total_mm_mean + Evaporation_SurfaceWater_mm_mean + - Evaporation_InterceptedByVegetation_mm_mean + - Evaporation_InterceptedByLitter_mm_mean + Snowloss_mm_mean)) + temp <- all.equal( + x[, "Evaporation_Total_mm_mean"], + x[, "Evaporation_Soil_Total_mm_mean"] + + x[, "Evaporation_SurfaceWater_mm_mean"] + + x[, "Evaporation_InterceptedByVegetation_mm_mean"] + + x[, "Evaporation_InterceptedByLitter_mm_mean"] + + x[, "Snowloss_mm_mean"] + ) if (!isTRUE(temp)) { temp <- list("Etotal == Esoil + Eponded + Eveg + Elitter + Esnow" = temp) @@ -449,9 +458,12 @@ check_aggregated_output <- function(x) { # (7) E(soil) + Ttotal = infiltration - (deepDrainage + delta(swc)) - temp <- with(x, all.equal(Evaporation_Soil_Total_mm_mean + - Transpiration_Total_mm_mean, Infiltration_mm_mean - - (DeepDrainage_mm_mean + SWC_StorageChange_mm_mean))) + temp <- all.equal( + x[, "Evaporation_Soil_Total_mm_mean"] + + x[, "Transpiration_Total_mm_mean"], + x[, "Infiltration_mm_mean"] - + (x[, "DeepDrainage_mm_mean"] + x[, "SWC_StorageChange_mm_mean"]) + ) if (!isTRUE(temp)) { temp <- list("Esoil + Ttotal == infiltration - (deepDrainage + delta(swc))" diff --git a/R/WeatherDB.R b/R/WeatherDB.R index 97d87ab4..213e28d1 100644 --- a/R/WeatherDB.R +++ b/R/WeatherDB.R @@ -459,7 +459,7 @@ writeMonthlyClimate <- function(id, siteDirsC) { 1L } -create_filename_for_Maurer2002_NorthAmerica <- function(X_WGS84, Y_WGS84) { # nolint +create_filename_for_Maurer2002_NorthAmerica <- function(X_WGS84, Y_WGS84) { origin <- 28.8125 res <- 0.125 xtemp <- origin + round((X_WGS84 - origin) / res, 0) * res @@ -517,7 +517,7 @@ ExtractLookupWeatherFolder <- function(dir.weather, weatherfoldername, #' fluxes and states for the conterminous United States. Journal of Climate #' 15:3237-3251. #' @export -ExtractGriddedDailyWeatherFromMaurer2002_NorthAmerica <- function(dir_data, # nolint +ExtractGriddedDailyWeatherFromMaurer2002_NorthAmerica <- function(dir_data, cellname, start_year, end_year, dbW_digits, verbose = FALSE) { if (verbose) { @@ -730,7 +730,7 @@ get_DayMet_NorthAmerica <- function(dir_data, cellID, Xdm_WGS84, Ydm_WGS84, #' objects. #' @rdname ExtractDayMet #' @export -ExtractGriddedDailyWeatherFromDayMet_NorthAmerica_swWeather <- function( # nolint +ExtractGriddedDailyWeatherFromDayMet_NorthAmerica_swWeather <- function( dir_data, site_ids, coords_WGS84, start_year, end_year, dbW_digits) { # Check requested years @@ -775,7 +775,7 @@ ExtractGriddedDailyWeatherFromDayMet_NorthAmerica_swWeather <- function( # nolin #' #' @name ExtractDayMet #' @export -ExtractGriddedDailyWeatherFromDayMet_NorthAmerica_dbW <- function(dir_data, # nolint +ExtractGriddedDailyWeatherFromDayMet_NorthAmerica_dbW <- function(dir_data, site_ids, site_ids_by_dbW, coords_WGS84, start_year, end_year, dir_temp = tempdir(), dbW_compression_type = "gzip", dbW_digits, verbose = FALSE) { @@ -877,7 +877,7 @@ ExtractGriddedDailyWeatherFromDayMet_NorthAmerica_dbW <- function(dir_data, # no #' list is copied to the weather database. Units are [degree Celsius] for #' temperature and [cm / day] and for precipitation. #' @export -ExtractGriddedDailyWeatherFromNRCan_10km_Canada <- function(dir_data, site_ids, # nolint +ExtractGriddedDailyWeatherFromNRCan_10km_Canada <- function(dir_data, site_ids, site_ids_by_dbW, coords_WGS84, start_year, end_year, dir_temp = tempdir(), dbW_compression_type = "gzip", dbW_digits, verbose = FALSE) { @@ -1287,7 +1287,7 @@ get_NCEPCFSR_data <- function(dat_sites, daily = FALSE, monthly = FALSE, #' Computational and Information Systems Laboratory. #' \url{http://dx.doi.org/10.5065/D6513W89}. #' @export -GriddedDailyWeatherFromNCEPCFSR_Global <- function(site_ids, site_ids_by_dbW, # nolint +GriddedDailyWeatherFromNCEPCFSR_Global <- function(site_ids, site_ids_by_dbW, dat_sites, tag_WeatherFolder, start_year, end_year, meta_cfsr, n_site_per_core = 100, rm_temp = TRUE, resume = FALSE, dir_temp = tempdir(), dbW_compression_type = "gzip", dbW_digits, verbose = FALSE, @@ -1394,7 +1394,7 @@ GriddedDailyWeatherFromNCEPCFSR_Global <- function(site_ids, site_ids_by_dbW, # #' #' @author Charles Duso \email{cd622@@nau.edu} #' @export -extract_daily_weather_from_livneh <- function(dir_data, dir_temp, site_ids, # nolint +extract_daily_weather_from_livneh <- function(dir_data, dir_temp, site_ids, site_ids_by_dbW, coords, start_year, end_year, f_check = TRUE, backup = TRUE, comp_type = "gzip", dbW_digits = 2, verbose = FALSE) { @@ -1933,7 +1933,7 @@ dw_determine_sources <- function(dw_source, exinfo, dw_avail_sources, } -set_paths_to_dailyweather_datasources <- function(SFSW2_prj_meta) { # nolint +set_paths_to_dailyweather_datasources <- function(SFSW2_prj_meta) { dir_dW <- SFSW2_prj_meta[["project_paths"]][["dir_ex_weather"]] diff --git a/R/WeatherDB_Check.R b/R/WeatherDB_Check.R index 5c856647..45bf71b8 100644 --- a/R/WeatherDB_Check.R +++ b/R/WeatherDB_Check.R @@ -539,7 +539,8 @@ check_weatherDB <- function(dir_prj, fdbWeather, repeats = 2L, identical(failed, iNAs) print(paste0("Unsuccessful extractions: n = ", sum(failed), "; f = ", signif(sum(failed) / length(failed), 2))) - with(climate[failed, ], plot(Site_id_by_dbW, Scenario_id)) # nolint + tmp <- climate[failed, ] + plot(tmp[, "Site_id_by_dbW"], tmp[, "Scenario_id"]) failed_siteID <- climate[failed, "Site_id_by_dbW"] print(paste0("Sites with at least one unsuccessful extractions: n = ", diff --git a/R/WorkDatabase.R b/R/WorkDatabase.R index 04db45c0..ae1409a7 100644 --- a/R/WorkDatabase.R +++ b/R/WorkDatabase.R @@ -94,7 +94,7 @@ colnames_work_dbWork <- function() { "inwork", "time_s") } -colnames_modification_status_dbWork <- function() { # nolint +colnames_modification_status_dbWork <- function() { c("status", "time_stamp") } diff --git a/inst/WORDLIST b/inst/WORDLIST index a2812974..b5afac7b 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -17,6 +17,7 @@ abiotic additively arcmin arcsec +boreal Climatological corrigendum des @@ -120,6 +121,8 @@ Haugen Hopkinson Hornberger Itenfisu +Koeppen +Koeppen's L'Ecuyer Lange Lauenroth diff --git a/man/export_objects_to_workers.Rd b/man/export_objects_to_workers.Rd index 6c3d91b9..021dba81 100644 --- a/man/export_objects_to_workers.Rd +++ b/man/export_objects_to_workers.Rd @@ -10,7 +10,7 @@ export_objects_to_workers(obj_env, parallel_backend = c("mpi", "socket"), \arguments{ \item{obj_env}{An environment containing R objects to export.} -\item{parallel_backend}{A character vector, either \var{\dQuote{mpi}}' or +\item{parallel_backend}{A character vector, either \var{\dQuote{mpi}} or \var{\dQuote{socket}}} \item{cl}{A parallel (socket) cluster object} diff --git a/man/gather_objects_for_export.Rd b/man/gather_objects_for_export.Rd index c667858a..219738c3 100644 --- a/man/gather_objects_for_export.Rd +++ b/man/gather_objects_for_export.Rd @@ -2,15 +2,15 @@ % Please edit documentation in R/Parallel.R \name{gather_objects_for_export} \alias{gather_objects_for_export} -\title{Export R objects to MPI/socket workers} +\title{Export \var{R} objects to \var{MPI} or socket workers} \usage{ gather_objects_for_export(varlist, list_envs) } \arguments{ -\item{varlist}{A vector of R object names to export} +\item{varlist}{A vector of R object names to export.} -\item{list_envs}{A list of environments in which to search for the R objects} +\item{list_envs}{A list of environments in which to search for the R objects.} } \description{ -Export R objects to MPI/socket workers +Export \var{R} objects to \var{MPI} or socket workers } diff --git a/man/trewartha_climate.Rd b/man/trewartha_climate.Rd index 3f795c52..66294ce6 100644 --- a/man/trewartha_climate.Rd +++ b/man/trewartha_climate.Rd @@ -23,7 +23,7 @@ without group B--dry, include \itemize{ } \references{ Trewartha, G.T. and Lyle, H.H., 1980: An Introduction to Climate. - MacGraw - Hill, 5th Ed. Appendix: Koeppen's Classification of Climates + McGraw - Hill, 5th Ed. Appendix: Koeppen's Classification of Climates } \seealso{ \code{\link[ClimClass]{koeppen_geiger}} diff --git a/tests/testthat/test_OutputDatabase_DataAccess.R b/tests/testthat/test_OutputDatabase_DataAccess.R index a315a851..f9240a6b 100644 --- a/tests/testthat/test_OutputDatabase_DataAccess.R +++ b/tests/testthat/test_OutputDatabase_DataAccess.R @@ -12,6 +12,7 @@ test_that("dbOutput_add_calculated_field:", { data(iris) x <- data.frame(P_id = seq_len(nrow(iris)), iris) dbWriteTable(con, "iris", x) + dbDisconnect(con) # Test 1: 2 variables -> 1 variable, 1 additional parameter # Define function @@ -29,11 +30,12 @@ test_that("dbOutput_add_calculated_field:", { FUN = example_calc, delta = 2) # Check the new field + con <- dbConnect(SQLite(), dbOut_tmp) xout <- dbReadTable(con, "iris") + dbDisconnect(con) res2 <- example_calc(x[, vars_orig], delta = 2) expect_equivalent(xout[, "calc1"], res2) # Cleanup - dbDisconnect(con) unlink(dbOut_tmp) }) diff --git a/tests/testthat/test_rSFSW2_CodeStylePractices.R b/tests/testthat/test_rSFSW2_CodeStylePractices.R index 06fbef8f..2992516c 100644 --- a/tests/testthat/test_rSFSW2_CodeStylePractices.R +++ b/tests/testthat/test_rSFSW2_CodeStylePractices.R @@ -10,17 +10,7 @@ test_that("Package code style", { skip_if_not(identical(tolower(Sys.getenv("RSFSW2_ALLTESTS")), "true")) skip_on_cran() skip_on_appveyor() - # as of 2019-03-01 development is minimum version of lintr required for: - # - empty commas in multi-dimensional array subsetting, e.g., x[, , 1:3] - lintr_v <- unlist(utils::packageVersion("lintr")) - if (length(lintr_v) < 4 || isTRUE(lintr_v[4L] < 9000)) { - skip("Installed version of lintr is insufficient.") - } - - # as of 2019-03-11 `lintr` fails R-devel `_R_CHECK_LENGTH_1_LOGIC2_`, see - # https://github.com/jimhester/lintr/issues/377 (undo once this is fixed) - rctemp <- Sys.getenv("_R_CHECK_LENGTH_1_LOGIC2_") - Sys.setenv(`_R_CHECK_LENGTH_1_LOGIC2_` = "false") + skip_if_not_installed("lintr", minimum_version = "2.0.0") # Files that are not checked for lints files_not_tolint <- c( @@ -45,26 +35,22 @@ test_that("Package code style", { } else { # easier to work with interactively than `lintr::expect_lint_free` # additionally, `lintr::expect_lint_free` calls `lintr:::lint_package` - # which only considers code in "R", "tests", "inst", but not in "data-raw" - # or "demo" - dir_code <- file.path(pkg_path, c("data-raw", "demo", "R", "tests", "inst")) + # which only considers code in "R", "tests", "inst", but not in "data-raw", + # "doc", or "demo" + dir_code <- file.path(pkg_path, + c("data-raw", "demo", "R", "tests", "inst")) pkg_code_files <- list.files(path = dir_code, pattern = "\\.R$", ignore.case = TRUE, full.names = TRUE, recursive = TRUE) + pkg_code_files <- normalizePath(pkg_code_files) ids <- !(basename(pkg_code_files) %in% files_not_tolint) files_tolint <- pkg_code_files[ids] for (k in seq_along(files_tolint)) { - # 2019 Feb 27: this call to `lint` generates a number of warnings - # "argument is not a function" --> ignore for now because we include - # with `pkg_code_files` code that includes scripts etc. - suppressWarnings(badstyle <- lintr::lint(files_tolint[k])) + badstyle <- lintr::lint(files_tolint[k]) expect_identical(length(badstyle), 0L, info = print(badstyle)) } } - - # reset - Sys.setenv(`_R_CHECK_LENGTH_1_LOGIC2_` = rctemp) }) diff --git a/tests/testthat/test_rSFSW2_Spelling.R b/tests/testthat/test_rSFSW2_Spelling.R index bcb5c762..1af46476 100644 --- a/tests/testthat/test_rSFSW2_Spelling.R +++ b/tests/testthat/test_rSFSW2_Spelling.R @@ -15,8 +15,7 @@ test_that("Package spell checks", { # Spell check with `hunspell` as backend: # TODO: turn spell-checking on for vignettes - temp <- spelling::spell_check_package(pkg_path, vignettes = FALSE) - misspelled <- temp[["word"]] + misspelled <- spelling::spell_check_package(pkg_path, vignettes = FALSE) - expect_identical(length(misspelled), 0L, info = print(misspelled)) + expect_identical(length(misspelled[["word"]]), 0L, info = print(misspelled)) }) From 840ab788ea39209e7bf508b52337c9a3595234da Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Wed, 16 Oct 2019 17:55:42 -0400 Subject: [PATCH 16/21] Update unit test helper function --- tests/testthat/helper_testthat.R | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/testthat/helper_testthat.R b/tests/testthat/helper_testthat.R index bc065d7b..bfdfdd31 100644 --- a/tests/testthat/helper_testthat.R +++ b/tests/testthat/helper_testthat.R @@ -20,9 +20,7 @@ pkg_temp_dir <- function() { path <- file.path("..", "..") } - if (interactive() && requireNamespace("devtools") && - !devtools::is.package(path)) { - + if (!dir.exists(path) && interactive() && requireNamespace("devtools")) { path <- devtools::as.package(".")[["path"]] } From b624995b9b70d78588974e2b02a62ce69aeb19a4 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Wed, 16 Oct 2019 18:19:46 -0400 Subject: [PATCH 17/21] Fix example codes so that `devtools::run_examples(fresh = TRUE)` is successful, i.e., `\dontrun{}` code is run --- R/OutputDatabase.R | 24 ++++++++++++++---------- R/OutputDatabase_DataAccess.R | 15 ++++++++++----- R/Simulation_Project.R | 6 ++++-- R/Testproject_Functions.R | 8 +++++--- R/WorkDatabase.R | 20 +++++++++++--------- R/netCDF_prepare_climatedata_files.R | 10 ++++++---- man/compare_test_output.Rd | 8 +++++--- man/dbOut_check_values.Rd | 12 +++++++----- man/dbOut_update_values.Rd | 12 +++++++----- man/dbOutput_add_calculated_field.Rd | 15 ++++++++++----- man/dbWork_report_completion.Rd | 13 +++++++------ man/is_project_script_file_recent.Rd | 6 ++++-- man/prepare_climatedata_netCDFs.Rd | 10 ++++++---- man/recreate_dbWork.Rd | 7 ++++--- 14 files changed, 100 insertions(+), 66 deletions(-) diff --git a/R/OutputDatabase.R b/R/OutputDatabase.R index fa4d1c13..35f190ee 100644 --- a/R/OutputDatabase.R +++ b/R/OutputDatabase.R @@ -3395,6 +3395,7 @@ dbOut_prepare1 <- function(dbOut_fname, dbNew_fname, fields_include = NULL, #' #' @examples #' \dontrun{ +#' if (requireNamespace("RSQLite") && exists("SFSW2_prj_meta")) { #' con_dbCheck <- dbOut_check_values( #' dbOut_fname = SFSW2_prj_meta[["fnames_out"]][["dbOutput"]], #' dbNew_fname = "path/to/new.sqlite3", @@ -3404,20 +3405,21 @@ dbOut_prepare1 <- function(dbOut_fname, dbNew_fname, fields_include = NULL, #' ) #' ) #' -#' tables <- dbListTables(con_dbCheck) +#' tables <- RSQLite::dbListTables(con_dbCheck) #' tables <- tables[1] # example table -#' fields <- dbQuoteIdentifier(con_dbCheck, dbListFields(con_dbCheck, tables)) +#' fields <- RSQLite::dbQuoteIdentifier(con_dbCheck, +#' RSQLite::dbListFields(con_dbCheck, tables)) #' #' # Extract Pids from records that matched up for example table #' sql <- paste("SELECT P_id FROM", tables, "WHERE", #' paste(fields[-1], "= 1", collapse = " AND ")) -#' is_good <- dbGetQuery(con_dbCheck, sql) +#' is_good <- RSQLite::dbGetQuery(con_dbCheck, sql) #' #' # Extract Pids from records that did not match up; this should be empty #' sql <- paste("SELECT P_id FROM", tables, "WHERE", #' paste(fields[-1], "= 0", collapse = " OR ")) -#' is_bad <- dbGetQuery(con_dbCheck, sql) -#' } +#' is_bad <- RSQLite::dbGetQuery(con_dbCheck, sql) +#' }} #' #' @export dbOut_check_values <- function(dbOut_fname, dbNew_fname, fields_check = NULL, @@ -3540,6 +3542,7 @@ dbOut_check_values <- function(dbOut_fname, dbNew_fname, fields_check = NULL, #' #' @examples #' \dontrun{ +#' if (requireNamespace("RSQLite") && exists("SFSW2_prj_meta")) { #' table <- dbOut_update_values( #' dbOut_fname = SFSW2_prj_meta[["fnames_out"]][["dbOutput"]], #' dbNew_fname = "path/to/new.sqlite3", @@ -3547,16 +3550,17 @@ dbOut_check_values <- function(dbOut_fname, dbNew_fname, fields_check = NULL, #' aggregation_overall_mean = c("MAT_C_mean", "MAP_mm_mean"), #' aggregation_overall_sd = c("MAT_C_sd", "MAP_mm_sd"))) #' -#' con <- dbConnect(SQLite(), SFSW2_prj_meta[["fnames_out"]][["dbOutput"]]) -#' fields <- dbQuoteIdentifier(con, dbListFields(con, table)) +#' con <- RSQLite::dbConnect(RSQLite::SQLite(), +#' SFSW2_prj_meta[["fnames_out"]][["dbOutput"]]) +#' fields <- RSQLite::dbQuoteIdentifier(con, RSQLite::dbListFields(con, table)) #' #' # Extract Pids from records that were updated #' sql <- paste("SELECT P_id FROM", table, "WHERE", #' paste(fields[-1], "= 1", collapse = " AND ")) -#' is_good <- dbGetQuery(con, sql) +#' is_good <- RSQLite::dbGetQuery(con, sql) #' -#' dbDisconnect(con) -#' } +#' RSQLite::dbDisconnect(con) +#' }} #' #' @export dbOut_update_values <- function(dbOut_fname, dbNew_fname, fields_update = NULL, diff --git a/R/OutputDatabase_DataAccess.R b/R/OutputDatabase_DataAccess.R index 44356046..372859a6 100644 --- a/R/OutputDatabase_DataAccess.R +++ b/R/OutputDatabase_DataAccess.R @@ -40,12 +40,14 @@ #' @return The function is called for its side-effects on \code{dbOut_fname}. #' #' @examples -#' # Prepare databse +#' if (requireNamespace("RSQLite")) { +#' # Prepare database #' dbOut_tmp <- tempfile(fileext = ".sqlite") -#' con <- dbConnect(SQLite(), dbOut_tmp) +#' con <- RSQLite::dbConnect(RSQLite::SQLite(), dbOut_tmp) #' data(iris) #' x <- data.frame(P_id = seq_len(nrow(iris)), iris) -#' dbWriteTable(con, "iris", x) +#' RSQLite::dbWriteTable(con, "iris", x) +#' RSQLite::dbDisconnect(con) #' #' # Define calculation function #' vars_orig <- c("Sepal.Length", "Sepal.Width") @@ -62,13 +64,16 @@ #' FUN = example_calc, delta = 2) #' #' # Check the new field -#' xout <- dbReadTable(con, "iris") +#' con <- RSQLite::dbConnect(RSQLite::SQLite(), dbOut_tmp) +#' xout <- RSQLite::dbReadTable(con, "iris") +#' RSQLite::dbDisconnect(con) +#' #' res2 <- example_calc(x[, vars_orig], delta = 2) #' all.equal(xout[, "calc"], res2) #' #' # Cleanup -#' dbDisconnect(con) #' unlink(dbOut_tmp) +#' } #' #' @export dbOutput_add_calculated_field <- function(dbOut_fname, table, diff --git a/R/Simulation_Project.R b/R/Simulation_Project.R index 61a8d3b7..56470ea2 100644 --- a/R/Simulation_Project.R +++ b/R/Simulation_Project.R @@ -116,8 +116,10 @@ setup_rSFSW2_project_infrastructure <- function(dir_prj, verbose = TRUE, #' #' @examples #' \dontrun{ -#' is_project_script_file_recent( -#' dir_prj = SFSW2_prj_meta[["project_paths"]][["dir_prj"]])} +#' if (exists("SFSW2_prj_meta")) { +#' is_project_script_file_recent( +#' dir_prj = SFSW2_prj_meta[["project_paths"]][["dir_prj"]]) +#' }} is_project_script_file_recent <- function(dir_prj, script = "SFSW2_project_descriptions.R", ...) { diff --git a/R/Testproject_Functions.R b/R/Testproject_Functions.R index eb8637bc..2d34a0d0 100644 --- a/R/Testproject_Functions.R +++ b/R/Testproject_Functions.R @@ -505,10 +505,12 @@ check_aggregated_output <- function(x) { #' \dontrun{ #' # Run test project 4 inside development version of package #' # Assume that working directory is `tests/test_data/TestPrj4/` -#' source("SFSW2_project_code.R") +#' if (file.exists("SFSW2_project_code.R")) { +#' source("SFSW2_project_code.R") #' -#' # Compare output database with reference database -#' comp <- compare_test_output(".", dir_ref = "../0_ReferenceOutput/") +#' # Compare output database with reference database +#' comp <- compare_test_output(".", dir_ref = "../0_ReferenceOutput/") +#' } #' } #' #' @export diff --git a/R/WorkDatabase.R b/R/WorkDatabase.R index ae1409a7..8a0ee35b 100644 --- a/R/WorkDatabase.R +++ b/R/WorkDatabase.R @@ -607,12 +607,13 @@ dbWork_check_run <- function(path, runIDs) { #' @examples #' \dontrun{ #' # `SFSW2_prj_meta` object as produced, e.g., for `TestPrj4` -#' dbWork_report_completion( -#' path = SFSW2_prj_meta[["project_paths"]][["dir_out"]], -#' use_granular_control = -#' SFSW2_prj_meta[["opt_out_fix"]][["use_granular_control"]], -#' SFSW2_prj_meta = SFSW2_prj_meta) -#' } +#' if (exists("SFSW2_prj_meta")) { +#' dbWork_report_completion( +#' path = SFSW2_prj_meta[["project_paths"]][["dir_out"]], +#' use_granular_control = +#' SFSW2_prj_meta[["opt_out_fix"]][["use_granular_control"]], +#' SFSW2_prj_meta = SFSW2_prj_meta) +#' }} #' #' @export dbWork_report_completion <- function(path, use_granular_control = FALSE, @@ -791,9 +792,10 @@ dbWork_check_design <- function(path, use_granular_control = FALSE) { #' #' @examples #' \dontrun{ -#' # `SFSW2_prj_meta` object as produced, e.g., for `TestPrj4` -#' recreate_dbWork(SFSW2_prj_meta = SFSW2_prj_meta) -#' } +#' if (exists("SFSW2_prj_meta")) { +#' # `SFSW2_prj_meta` object as produced, e.g., for `TestPrj4` +#' recreate_dbWork(SFSW2_prj_meta = SFSW2_prj_meta) +#' }} #' #' @export recreate_dbWork <- function(path, dbOutput, use_granular_control, diff --git a/R/netCDF_prepare_climatedata_files.R b/R/netCDF_prepare_climatedata_files.R index 0e9cfb16..2c31dbb2 100755 --- a/R/netCDF_prepare_climatedata_files.R +++ b/R/netCDF_prepare_climatedata_files.R @@ -224,10 +224,12 @@ time_agrees_with_ncfilename <- function(filename, ftime) { #' dir_scrutinize <- file.path(dir_prj, "to_scrutinize") #' dir_out <- file.path(dir_prj, "..", "ClimateScenarios", "CMIP5", #' "ESGF_Global") -#' prepare_climatedata_netCDFs(dir_code, dir_data, dir_duplicates, -#' dir_concatables, dir_delete, dir_scrutinize, dir_out, -#' climDB_tag = "CMIP5_ESGF_Global") -#' } +#' if (all(dir.exists(dir_prj))) { +#' prepare_climatedata_netCDFs(dir_code, dir_data, dir_duplicates, +#' dir_concatables, dir_delete, dir_scrutinize, dir_out, +#' climDB_tag = "CMIP5_ESGF_Global") +#' }} +#' #' @export prepare_climatedata_netCDFs <- function(dir_code, dir_data, dir_duplicates, dir_concatables, dir_delete, dir_scrutinize, dir_out, climDB_tag = NULL, diff --git a/man/compare_test_output.Rd b/man/compare_test_output.Rd index cec048ea..f7203900 100644 --- a/man/compare_test_output.Rd +++ b/man/compare_test_output.Rd @@ -25,10 +25,12 @@ the file name. \dontrun{ # Run test project 4 inside development version of package # Assume that working directory is `tests/test_data/TestPrj4/` - source("SFSW2_project_code.R") + if (file.exists("SFSW2_project_code.R")) { + source("SFSW2_project_code.R") - # Compare output database with reference database - comp <- compare_test_output(".", dir_ref = "../0_ReferenceOutput/") + # Compare output database with reference database + comp <- compare_test_output(".", dir_ref = "../0_ReferenceOutput/") + } } } diff --git a/man/dbOut_check_values.Rd b/man/dbOut_check_values.Rd index 03fbfdf3..1b2bd750 100644 --- a/man/dbOut_check_values.Rd +++ b/man/dbOut_check_values.Rd @@ -40,6 +40,7 @@ database } \examples{ \dontrun{ +if (requireNamespace("RSQLite") && exists("SFSW2_prj_meta")) { con_dbCheck <- dbOut_check_values( dbOut_fname = SFSW2_prj_meta[["fnames_out"]][["dbOutput"]], dbNew_fname = "path/to/new.sqlite3", @@ -49,19 +50,20 @@ database ) ) - tables <- dbListTables(con_dbCheck) + tables <- RSQLite::dbListTables(con_dbCheck) tables <- tables[1] # example table - fields <- dbQuoteIdentifier(con_dbCheck, dbListFields(con_dbCheck, tables)) + fields <- RSQLite::dbQuoteIdentifier(con_dbCheck, + RSQLite::dbListFields(con_dbCheck, tables)) # Extract Pids from records that matched up for example table sql <- paste("SELECT P_id FROM", tables, "WHERE", paste(fields[-1], "= 1", collapse = " AND ")) - is_good <- dbGetQuery(con_dbCheck, sql) + is_good <- RSQLite::dbGetQuery(con_dbCheck, sql) # Extract Pids from records that did not match up; this should be empty sql <- paste("SELECT P_id FROM", tables, "WHERE", paste(fields[-1], "= 0", collapse = " OR ")) - is_bad <- dbGetQuery(con_dbCheck, sql) -} + is_bad <- RSQLite::dbGetQuery(con_dbCheck, sql) +}} } diff --git a/man/dbOut_update_values.Rd b/man/dbOut_update_values.Rd index ed427d01..0c92dbf2 100644 --- a/man/dbOut_update_values.Rd +++ b/man/dbOut_update_values.Rd @@ -39,6 +39,7 @@ Update values of \var{dbOutput} based on a new database } \examples{ \dontrun{ +if (requireNamespace("RSQLite") && exists("SFSW2_prj_meta")) { table <- dbOut_update_values( dbOut_fname = SFSW2_prj_meta[["fnames_out"]][["dbOutput"]], dbNew_fname = "path/to/new.sqlite3", @@ -46,15 +47,16 @@ Update values of \var{dbOutput} based on a new database aggregation_overall_mean = c("MAT_C_mean", "MAP_mm_mean"), aggregation_overall_sd = c("MAT_C_sd", "MAP_mm_sd"))) - con <- dbConnect(SQLite(), SFSW2_prj_meta[["fnames_out"]][["dbOutput"]]) - fields <- dbQuoteIdentifier(con, dbListFields(con, table)) + con <- RSQLite::dbConnect(RSQLite::SQLite(), + SFSW2_prj_meta[["fnames_out"]][["dbOutput"]]) + fields <- RSQLite::dbQuoteIdentifier(con, RSQLite::dbListFields(con, table)) # Extract Pids from records that were updated sql <- paste("SELECT P_id FROM", table, "WHERE", paste(fields[-1], "= 1", collapse = " AND ")) - is_good <- dbGetQuery(con, sql) + is_good <- RSQLite::dbGetQuery(con, sql) - dbDisconnect(con) -} + RSQLite::dbDisconnect(con) +}} } diff --git a/man/dbOutput_add_calculated_field.Rd b/man/dbOutput_add_calculated_field.Rd index d6176e31..6ff592a4 100644 --- a/man/dbOutput_add_calculated_field.Rd +++ b/man/dbOutput_add_calculated_field.Rd @@ -51,12 +51,14 @@ calculation of values from (an) existing field(s) } \examples{ -# Prepare databse +if (requireNamespace("RSQLite")) { +# Prepare database dbOut_tmp <- tempfile(fileext = ".sqlite") -con <- dbConnect(SQLite(), dbOut_tmp) +con <- RSQLite::dbConnect(RSQLite::SQLite(), dbOut_tmp) data(iris) x <- data.frame(P_id = seq_len(nrow(iris)), iris) -dbWriteTable(con, "iris", x) +RSQLite::dbWriteTable(con, "iris", x) +RSQLite::dbDisconnect(con) # Define calculation function vars_orig <- c("Sepal.Length", "Sepal.Width") @@ -73,12 +75,15 @@ dbOutput_add_calculated_field( FUN = example_calc, delta = 2) # Check the new field -xout <- dbReadTable(con, "iris") +con <- RSQLite::dbConnect(RSQLite::SQLite(), dbOut_tmp) +xout <- RSQLite::dbReadTable(con, "iris") +RSQLite::dbDisconnect(con) + res2 <- example_calc(x[, vars_orig], delta = 2) all.equal(xout[, "calc"], res2) # Cleanup -dbDisconnect(con) unlink(dbOut_tmp) +} } diff --git a/man/dbWork_report_completion.Rd b/man/dbWork_report_completion.Rd index 584fc99c..42e8c5b9 100644 --- a/man/dbWork_report_completion.Rd +++ b/man/dbWork_report_completion.Rd @@ -29,11 +29,12 @@ Estimate percentage of completed runs \examples{ \dontrun{ # `SFSW2_prj_meta` object as produced, e.g., for `TestPrj4` -dbWork_report_completion( - path = SFSW2_prj_meta[["project_paths"]][["dir_out"]], - use_granular_control = - SFSW2_prj_meta[["opt_out_fix"]][["use_granular_control"]], - SFSW2_prj_meta = SFSW2_prj_meta) -} +if (exists("SFSW2_prj_meta")) { + dbWork_report_completion( + path = SFSW2_prj_meta[["project_paths"]][["dir_out"]], + use_granular_control = + SFSW2_prj_meta[["opt_out_fix"]][["use_granular_control"]], + SFSW2_prj_meta = SFSW2_prj_meta) +}} } diff --git a/man/is_project_script_file_recent.Rd b/man/is_project_script_file_recent.Rd index 38e853b2..e0d48940 100644 --- a/man/is_project_script_file_recent.Rd +++ b/man/is_project_script_file_recent.Rd @@ -25,6 +25,8 @@ installed \pkg{rSFSW2}-package version } \examples{ \dontrun{ -is_project_script_file_recent( - dir_prj = SFSW2_prj_meta[["project_paths"]][["dir_prj"]])} +if (exists("SFSW2_prj_meta")) { + is_project_script_file_recent( + dir_prj = SFSW2_prj_meta[["project_paths"]][["dir_prj"]]) +}} } diff --git a/man/prepare_climatedata_netCDFs.Rd b/man/prepare_climatedata_netCDFs.Rd index 6e9e7334..0872e6d5 100644 --- a/man/prepare_climatedata_netCDFs.Rd +++ b/man/prepare_climatedata_netCDFs.Rd @@ -25,8 +25,10 @@ dir_delete <- file.path(dir_prj, "to_delete") dir_scrutinize <- file.path(dir_prj, "to_scrutinize") dir_out <- file.path(dir_prj, "..", "ClimateScenarios", "CMIP5", "ESGF_Global") -prepare_climatedata_netCDFs(dir_code, dir_data, dir_duplicates, - dir_concatables, dir_delete, dir_scrutinize, dir_out, - climDB_tag = "CMIP5_ESGF_Global") -} +if (all(dir.exists(dir_prj))) { + prepare_climatedata_netCDFs(dir_code, dir_data, dir_duplicates, + dir_concatables, dir_delete, dir_scrutinize, dir_out, + climDB_tag = "CMIP5_ESGF_Global") +}} + } diff --git a/man/recreate_dbWork.Rd b/man/recreate_dbWork.Rd index 52943c36..51fedc3f 100644 --- a/man/recreate_dbWork.Rd +++ b/man/recreate_dbWork.Rd @@ -30,8 +30,9 @@ Re-create or update \var{\sQuote{dbWork}} based on \var{\sQuote{dbOutput}} } \examples{ \dontrun{ -# `SFSW2_prj_meta` object as produced, e.g., for `TestPrj4` -recreate_dbWork(SFSW2_prj_meta = SFSW2_prj_meta) -} +if (exists("SFSW2_prj_meta")) { + # `SFSW2_prj_meta` object as produced, e.g., for `TestPrj4` + recreate_dbWork(SFSW2_prj_meta = SFSW2_prj_meta) +}} } From f189d1109a7129bf896702b13d8ec95caaaa87c8 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Thu, 17 Oct 2019 08:33:23 -0400 Subject: [PATCH 18/21] Turn off the lintr-bot on travis-ci --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index f956be36..1a38bc92 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ env: - NOT_CRAN=false # secure `GITHUB_PAT` for drs to increase "GitHub API rate limit" - secure: "rq8iu0qkN0QYa1CF3zx/ub2eXJ1vc6XmOSqWPUSCHQTOuftUnKjbysAo0a8Cj1GqHPltXyIx8ZfLSJpN/zIsW919B3XBPSVeoStdpvJ/omUdGf8g4/0k2jlLQx0JpfFuIjOaFBlL5Kg5iAm3Xg1dxA/+cgx57KLbbF91HEvCE22g5NgO5ZEWsKH6iyVzEkz5o3sxvIxDEniiJSKdxfZLe8jrZNmqG+H2tKn1GbiDfunN8ynYE5Enwamr6y46E8Q2Bm7BR4FX3syxjvhz/JOi44vy88E50wKpMU+y9/lxpqMjQxM8lU0L5ZAxsSe08fM6jvEzOVZgsEVS3tMJHdCy9mQ3YktVl7l4hce4+OI866ZkkfpX2nBoGcjLe9LVbbGLet7UoC8DNv5XF1eJU+9sn5Ynr94YFaNhlFP2H+PoqWgyt7SLpgYjogrd8/X8a/oQeIMhriqNVbddc6oB2rkBsjRA9kGo+8jcHei80Xm/ZaIafMoa9KZV4Aw7Uhd/RP0JiaRQmL8mBf09/LOJD24LIpqYzgHJg6q6pHa/XS+9qcbjoObzbdy1rBtGiS5f1eXrCefTmsvSsOvRWlyZcGLrX2VbTFiLTjFCDWLjYNMUVCxhislsxZCrvRuMaS9IIep8rD+p8EDjUIr/UTq/vl64E1jfd3+3wA4rcW3nbQ6iiYg=" + - LINTR_COMMENT_BOT=false sudo: false cache: packages # sets `R_LIBS_USER` From a599530f96da0a8cf6d161df3c49108a5db3b313 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Thu, 17 Oct 2019 08:33:52 -0400 Subject: [PATCH 19/21] Fix formatting of documentation for `dbOut_update_values` --- R/OutputDatabase.R | 3 ++- man/dbOut_update_values.Rd | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/R/OutputDatabase.R b/R/OutputDatabase.R index 35f190ee..787cbba7 100644 --- a/R/OutputDatabase.R +++ b/R/OutputDatabase.R @@ -3552,7 +3552,8 @@ dbOut_check_values <- function(dbOut_fname, dbNew_fname, fields_check = NULL, #' #' con <- RSQLite::dbConnect(RSQLite::SQLite(), #' SFSW2_prj_meta[["fnames_out"]][["dbOutput"]]) -#' fields <- RSQLite::dbQuoteIdentifier(con, RSQLite::dbListFields(con, table)) +#' fields <- RSQLite::dbQuoteIdentifier(con, +#' RSQLite::dbListFields(con, table)) #' #' # Extract Pids from records that were updated #' sql <- paste("SELECT P_id FROM", table, "WHERE", diff --git a/man/dbOut_update_values.Rd b/man/dbOut_update_values.Rd index 0c92dbf2..671678f6 100644 --- a/man/dbOut_update_values.Rd +++ b/man/dbOut_update_values.Rd @@ -49,7 +49,8 @@ if (requireNamespace("RSQLite") && exists("SFSW2_prj_meta")) { con <- RSQLite::dbConnect(RSQLite::SQLite(), SFSW2_prj_meta[["fnames_out"]][["dbOutput"]]) - fields <- RSQLite::dbQuoteIdentifier(con, RSQLite::dbListFields(con, table)) + fields <- RSQLite::dbQuoteIdentifier(con, + RSQLite::dbListFields(con, table)) # Extract Pids from records that were updated sql <- paste("SELECT P_id FROM", table, "WHERE", From 66c1bbb28c1a6513077e2fe4b0515f0c12f45fd3 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Thu, 17 Oct 2019 09:23:00 -0400 Subject: [PATCH 20/21] Use `pkgload` instead of `devtools` to find package path --- tests/testthat/helper_testthat.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/helper_testthat.R b/tests/testthat/helper_testthat.R index bfdfdd31..2723dd21 100644 --- a/tests/testthat/helper_testthat.R +++ b/tests/testthat/helper_testthat.R @@ -20,8 +20,8 @@ pkg_temp_dir <- function() { path <- file.path("..", "..") } - if (!dir.exists(path) && interactive() && requireNamespace("devtools")) { - path <- devtools::as.package(".")[["path"]] + if (!dir.exists(path) && interactive() && requireNamespace("pkgload")) { + path <- pkgload::pkg_path() } path From eaef9d0bd43c5702fb4282487f98c750e880ff61 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Fri, 18 Oct 2019 17:26:28 -0400 Subject: [PATCH 21/21] Update to rSOILWAT2 v3.1.3 --- DESCRIPTION | 4 +- R/sysdata.rda | Bin 36175 -> 36488 bytes .../1_Input/treatments/tr_cloudin/climate.in | 27 +++- data-raw/1_Input/treatments/tr_prodin/veg.in | 116 ++++++++++----- .../treatments/tr_siteparamin/siteparam.in | 140 +++++++++--------- .../1_Input/treatments/tr_soilsin/soils.in | 53 ++++--- .../tr_weathersetupin/weathsetup.in | 23 ++- 7 files changed, 223 insertions(+), 140 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 589a8c41..9d46e30f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: rSFSW2 Title: Simulation Framework for SOILWAT2 Version: 4.1.0 -Date: 2019-10-16 +Date: 2019-10-18 Authors@R: c( person("Daniel", "Schlaepfer", email = "daniel.schlaepfer@yale.edu", comment = c(ORCID = "0000-0001-9973-2065"), role = c("aut", "cre")), @@ -14,7 +14,7 @@ Description: Setting up, carrying out, and analyzing ecosystem water balance Depends: R (>= 3.5.0) Imports: - rSOILWAT2 (>= 3.0.0), + rSOILWAT2 (>= 3.1.3), RSQLite (>= 2.1.1), DBI (>= 1.0), Rcpp (>= 0.12.12), diff --git a/R/sysdata.rda b/R/sysdata.rda index 803d57567eb0ef8cf7a5e19409afc831da45591c..b1efcd1fa7055b7c9baddad85fbebd0ffe39b646 100644 GIT binary patch literal 36488 zcmaf3Q*$MZvfZ&gv2EM7ZQHgnv2EL#*qqq*j;)EE^W9%?ySl2^%c}0T))LXN;${}s zrcl)u<_&}c5c>T5zqY4m2Amc7^v%EYT$>|%>E6=4ZtwQL&9S@e&FH$= zx-s;<^}pY4@XY_%n*B)d?AqwL-kj;%d6@0JDlj!PxO(Z{wb^kOSbwwiH|RF#>wW2a zn7R0HJ)NsqTdRASspo7uzuxS7>0Q0`0P^;pPTc#yZ1p|8;6Fci^Iu&66)rtyb%CDk zyU!<&Y?!$pIh`;5&mX%lJdH0i)||H53Jv~q-ePi;WYT_4{$ zTMwZBt-_{dO?!9Ft^eiN)_(7;`-|`HMeCfd!>XfC>)Fd#{xN#_T5s>R_gbIZ$<`Ie zTJN_vNi)_igQ#n`7OJz-jxG>r%-r@7Br7xZN9Ldvp;1 z<_vrQ@Sg)nQKEuW{||zi7&D0iDnR4<>Xn-u(0F)pANZ~w4Q6UXF2?eMzi-~dN z5(UM)JoOa?g(};~$jFe1i4jatCK?FaL@&{>O}5lE=ZZE|>8ovM!HfW*b?OK3kHLAf?DQF~KogC?_r*^06)l#bIX^ z=AejUGXoL3gH8YgKqr-ufER_I0ZAp=0bMeT&b*J!-yzyz`0#-M^*gaF&ukq1nW zAVi0ev8GWld%myGcqRZ+66kSoNWdthi1R3O2rJk=+X!^}cnW~zn<|7z=pPuK5Cax6 zR01+HH3}#b7YZ^GMg5mYiY-|&s#{EAuYRl>c(`!|<>k_|3tYQjra5{DAaaz1gcNIF z#Dp32zZe;bH6ld%AEXln83BNpjfe^1fnc10lHWnM8=>I+SFccXF8~n9$d4z4V#^p$ zqRAu!E(FS66*Pv$>4peP0SLyB8-RzGti9{yy78kPflh|6HxeU8NM#y+c~FFd`w3}- z0MXPkhIK+<#z;ZV=HPR1X8N74x1Fp6^&1y!oHHgrY7luf*^09{%Jq6(u=)=2BH*e8 z-moCDjcr-4)N!j1kkyO+r>pwZ&wrW;Jm|hjhpd=8)Qd3V``m#iO`8XXz*qvO_Q$dJ z-w%2#k`qprjbJ%H>qB<}pHQ?bkrN3x7LbTqJ2114g&N&al5J&9#SaGgN6r?8CG#$7DNcZ3<- z&hiG~zp^z)7H@X$M>ckvxZPASq1I7ua?wOXMwPAk*BU~HntDx}t-J0!L? zVPYZ$AABWs6~UwYJ8opq0(y}9&#(MiNY2|woQC{*Fl!VP6wez(B60D3`+%s^UhNwv zabOnx_o(BF)UgIHV9JvV85qSSpy1)5lqi0E@+J8e+pkciKbN0Ep z0}`i@wB})jFGbe)p8Y0Q#XaZVZoFFqYQbwSX6Ej&%D}@#Dj7m3WiTNYXh22fW^tz#`jJAg7>%?h9r`fOOzIneZQ1i=4D^7jW_76g6QXT}9s1NMf-@rAYt002Tu!M^UvZhH-B;Q^sK zv{&)4BgBXZz!BC=62ssXmMMpuZ&fL?ZIhSVZWEQR&(n5clQc%3H&ktMs#5B79qrO{ zPsy4dzHSLZtuO{VW$!s)56t{=ZWxiD+*1w7Jm$a><(n7B3%YY-Km?vyj@EY?>OTF! z0)W{Rg1E&fueWsFe_XCpSZ$DY#3=~payKCl+jKvNj!q^>*vVG9q$p|P=z#g$j3vqP z-nb_a(E-q5a3G#n1;~L0LgFR$N*sNE&-R>8FP*tRlx@TukYN?51;Wyx?hDVoE;?1v4@Y8HqkLlOrWHD1-#@80TcXDV8*9vjZN zf)#mX*gORI@9My-#bUl%YX?1f zsI*bvq{t5G|9TDpKnsk@`Lq-cQ=0|9t=t} zo`w<&|LKXZGp<Jk#r3+4=Kjsiz*nBeAMM$TP$Iu(Yu@ftkT^kl`KeoF1ff4O z;CjRe_l~JG3iTS5_f>7A^nB}8fY$EdG)?ew#^m@zAaerzyjyIE$a_?v^Mjoz^TT`t zfCfLw#1A21?ODRZwU#zE$}`eoI`Zf znzb5XGps+hd{m~EFw=%LOptK*F}zG)ooN+w?XiZF`=d?&>^{R(%-g(_CV~g>OT7O< zXNPY2t4!dOW2BcveMqpTho1c0TADDUvd#5`Au!EFf7U#L`Yjrt#jJ!$NI&;}suq&9 z+F*J5kZUaTS_dhdM@Exw=yt8&{#!Dd)mNJEA+8^y9gQ@<_)Ny0R*Cl%+2MQSqdmVy zVlVGU{8FFCODly=9}#^-r>8@xTdg0DdXc;TkZ2EZQ173n`rR0O$Ft$7Z~&6k@$IY_ zi!4mmX7>2g)))6X1pGAroh7k`h9doO^pgZPzZ)U1iX5eU2^{$yI`gEvx~<~)3jpmi z3A&0yikLmu$O~N|doE8qI(P^&tJmUrduQvqz*eLoaE1a@`{AV;ZXKoLbs0Kg7NXj~ z@}|>Fx;GLQ(gTQ3{2|6)B%$BMj?cWwFZ31T5m4^jn}s7Hlmn1~tLNN$%zMcK1r#Mo zzA0!RmOV`I3!mAbkX!FNd}lUlj!)}n8ber-c~`OLqNtit?d{MSY;$RCg@SksR3Lu~ zn_c0PuI*{eU!$f-U{EIA4h(c77tNRWrKH5Eye#*Yhas&QPbY0iaUEaV{|)zV*&Y4F z0(G38ngQ6h!xhw?V5{goio9Ru_)XNN)Y|;Jq!Y~_DRq(eKe;S{pWb`NaztY^*LL@v zR``qz+%$~-R3G!`>}#&g+Ja4-@Gu=Xil1Sym}R4`pg$(tA~6Sf>M|nj-ttd~z_yZ! zPNushPKpi8Tu~_xAIf*zmFy;=W2<)*P*nTOQ>VpQdQHbo z=z^-c6eo_6>WotR2nPTF(8Q!XZb`w>II)})qhFlX^@ppWMOEZ9P@)-s8P}@HS|01c zWbaO}c#!xFa>;iNOZr=W+xzMNc81$A?&?bK2V{Sa-D9kQ$BZg3U zN;vHSKc;0z3_szF&WkcspD>>>K3NF9QI>gAk-SyQvw!x^HjJKkh|zi5T26gzRyrBd zi6GuI0=#_lP#n);NRq7*Nj{w%_`m)!CBjxuNXHQQzc9Gx%4pm4XTHj+%`d)qFv$Tv4NWlTt? zxP=_R&poBHuNaDHksD`g8Ou~}XoYFQ3&;>foovoYh9Ke*3-+c(Fwgq?xc%wWh0l3QqICj6lVSYTKf5cD*A*_vNV!#5>c! zc)gp9xuS5MF?Oc@`n@oK{Gek=qbZ!R+tESCD3ZoPO8SQJWx2)S*@t`AiRxiC=9^b7 z#si)g$9C$oU%iC#1?)R%zGH`C&$&{d{#|sxq)csL5lt54g{w;m1l^($Tix4_Bb4o& zN{Yi^_w6}Sf-@LRAMJK?v*@#?0hl{>^AS~hLm1Qtm>v`>r)iJt5J|||Qk_re>rYw7 z2+216j0X0;v7%?$*GdIsXg>bYy0YaZq{^E-Htm~6D1HPVS_&gc--)V>JdIhYql@uz zSW!r>(57JP=v!Rz{c+4I0>6V8mF{vK15Ng#4~hCpazzdz0xAE6e9OFE$K(TxG`A)O zjC@dV5VE=<0WzDo&om`_uL;7>C4P-*qvk4vDK?+b3(;x}BMF>a{3dic4W+laX~ z#h^JCImD(7NAoT#wxPNoUW5cAy5CvT|AmWN9TzdIwC=c<@yx?Un^$LZPA6D6XAm0?u)`9D2$$5!U=b-tTvT#Dh8L8Fe|7( z`ghm8BEW%*hi`c!z2laiZXwu{SbEL&-kb{r1<|!}!mcx#I`>2Bmx%qtf5VzdUz2_Y z`n<;eMcfxF`aoZZNM4m2M4FPnz%pF!Hkx#&igH zkFGRg-v~6R>9(OKi`W7$A}+}=6qSpJ9$$$Vqi`p~gKJrsnaziIC;S!tbmMEc0ZD#J zk|K7xJ%Nkas6CH&TXyT$aD5c=c}P_v0PT{A{EW5h5i8WED9S6v!}_2{y*tb3Pgi+_ z<|;n+&oFn$*-yFl`4#*47J3rOY8*2sJ_1(O5NcI6Ow(Ny*ReghW#jbog?2uI(^>N6 z44c*C2~$3u|2V#1ddfQ}`-d-09LmG5fOt$uS|*TsxS7ulJRX({0CeviJwG_BDyT2` zH;zjD!Pdy2bIO6Dw&&I!N--;s{Y@wvxD&H?FfRc?>gRf4Nd`vP`8AHM6kX2nD= zgB-osfeCd1sh2(SWntu?Lv91XFG-3WD;iDWV3oGu;(117yK_N?&8Dyt9G9n0G0iF5k zN!W!iUGdnwo(1U=C{BS?4>&9I$iRTaH%Fn&atJx)Cn$zW7_-LY5M{%3w*ju*h{E`O zJmZ~k-bR;9ks*S@7-;{*mpJqbV}tslA?G$R48j2NyZ1k4Gkho2pOyM>a}5tF!LCwJ zu$T5zsM4QCTX3=Hix5U7uhd}Z?sqB{b`G4to2)jAGQDH1;Wl$60{xs?tmpb%Op9Pp zM9?ZTD2-G=kQ{*nt$zrnlXuIoMcSC4L~oI&HPja0F#QT9#6gW(V%zUb1vmhyor{{? z?9mG!So;u8V2dv$#VbTH_Rte*EbXRr>1#KEzoV6F5L;0$5i7}=9)>w1Sr*^)&ed!WT}+miq_Mqs{m-L+Hs&BT zqMxEeZiYYO$O>h>)22Psf$zN-g!)>AIFm~dsuutmtK{xxR<+6h9FJRG{kQtgq(C6s z8NoTR(5_j7Z)68+!fbkcw=$m}t3>t~<4YC*6cDerkhT4%5d6b3lDVRL2-R+nE#Llx z9rJdr0~{J`*OqWYr4A;x>5sF33dYeiv3^}%B->!eD?%hkH;fiM;xD@z05n$|RRoX= znwpBlESamk)0z^hf{is101hU~HYNo#U=e}$HT&Vpe<(u0_%)@6`#hcax5HyRRzD!> znXqf^yCKTGlgwlWrXViBLgbej{Ya~1F4!6yAR!2x#CHS);dm+iAum6GYvhzT;po`% z)uF|^pajXD7E0r8586n6@cpuX5>GYm6!b>!Up=UnP`qQdt&X~r?xC>eoAnSh1(hK4 zJv+VD%}7H=k7t0WDvD>dWbV-APFYK=e{sFsE^@f8bk10@`&Rj01ZD(W>a11 zYjHygO3rrR{aF=<%3ZO53AFb)6(sh~7r)sBkW+T6-$@{SbH{_V8U6c?DWHTFL62_hqWTT|w0>T51Fp&!j{Gf9hGnW_3F>&gH847()HCa<{UUbIuK)%a6R9qQWN?0gY@<+gN8{H+ z!)*C|HgNa|zvwr6gzb_D5?|lr ze;ev#gx_33*P7I2tu+Nu1Qb;an^$Hr2H*pHPRimJiNuoyZwVz%0AXw!XdDR~A>M=q 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 C+fXzB literal 36175 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¨?k7{dQW>z5!& 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 DTURFe diff --git a/data-raw/1_Input/treatments/tr_cloudin/climate.in b/data-raw/1_Input/treatments/tr_cloudin/climate.in index 5e050207..758b863f 100644 --- a/data-raw/1_Input/treatments/tr_cloudin/climate.in +++ b/data-raw/1_Input/treatments/tr_cloudin/climate.in @@ -1,6 +1,21 @@ -71.0 61.0 61.0 51.0 41.0 31.0 23.0 23.0 31.0 41.0 61.0 61.0 # (site: testing), sky cover (sunrise-sunset),%,Climate Atlas of the US,http://cdo.ncdc.noaa.gov/cgi-bin/climaps/climaps.pl -1.3 2.9 3.3 3.8 3.8 3.8 3.3 3.3 2.9 1.3 1.3 1.3 # Wind speed (m/s),Climate Atlas of the US,http://cdo.ncdc.noaa.gov/cgi-bin/climaps/climaps.pl -61.0 61.0 61.0 51.0 51.0 51.0 41.0 41.0 51.0 51.0 61.0 61.0 # rel. Humidity (%),Climate Atlas of the US,http://cdo.ncdc.noaa.gov/cgi-bin/climaps/climaps.pl -1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 # transmissivity (rel), only used in petfunc, but falls out of the equations (a = trans * b, c = a / trans) -213.7 241.6 261.0 308.0 398.1 464.5 0.0 0.0 0.0 140.0 161.6 185.1 # snow density (kg/m3): Brown, R. D. and P. W. Mote. 2009. The response of Northern Hemisphere snow cover to a changing climate. Journal of Climate 22:2124-2145. -1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 # m = number of precipitation events per day +#------ Input file for mean monthly atmospheric parameters + +# Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec + +# Sky cover (sunrise-sunset; percent) +71.0 61.0 61.0 51.0 41.0 31.0 23.0 23.0 31.0 41.0 61.0 61.0 + +# Wind speed (m / s) +1.3 2.9 3.3 3.8 3.8 3.8 3.3 3.3 2.9 1.3 1.3 1.3 + +# Relative humidity (%) +61.0 61.0 61.0 51.0 51.0 51.0 41.0 41.0 51.0 51.0 61.0 61.0 + +# Atmospheric transmissivity (relative) +1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 + +# Snow density (kg / m3) +213.7 241.6 261.0 308.0 398.1 464.5 0.0 0.0 0.0 140.0 161.6 185.1 + +# Number of precipitation events per day +1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 diff --git a/data-raw/1_Input/treatments/tr_prodin/veg.in b/data-raw/1_Input/treatments/tr_prodin/veg.in index 82783a4a..51e67b31 100755 --- a/data-raw/1_Input/treatments/tr_prodin/veg.in +++ b/data-raw/1_Input/treatments/tr_prodin/veg.in @@ -1,18 +1,34 @@ -# Plant production data file for SOILWAT2 -# Location: +#------ Input file for land cover and vegetation types: +# parameters and mean monthly biomass values -# ---- Composition of vegetation type components (0-1; must add up to 1) -# Grasses Shrubs Trees Forbs BareGround +# USER: The vegetation composition and the mean monthly biomass values should +# be adjusted for site-specific run conditions. + +# USER: Most of the other values in this file are parameters that +# describe the four available vegetation types and should not be +# modified unless a vegetation type itself is altered. + + +#---- Composition of vegetation type components (0-1; must add up to 1) +# Grasses Shrubs Trees Forbs BareGround 0.2 0.2 0.2 0.2 0.2 -# ---- Albedo -# Grasses Shrubs Trees Forbs BareGround - 0.167 0.143 0.106 0.167 0.15 # albedo: (Houldcroft et al. 2009) MODIS snowfree 'grassland', 'open shrub', ‘evergreen needle forest’ with MODIS albedo aggregated over pure IGBP cells where NDVI is greater than the 98th percentile NDVI +#---- Albedo +# Default values from Houldcroft et al. 2009: +# MODIS snowfree 'grassland', 'open shrub', ‘evergreen needle forest’ with +# MODIS albedo aggregated over pure IGBP cells where NDVI is greater than +# the 98th percentile NDVI + +# Grasses Shrubs Trees Forbs BareGround + 0.167 0.143 0.106 0.167 0.15 -# -- Canopy height (cm) parameters either constant through season or as tanfunc with respect to biomass (g/m^2) -# Grasses Shrubs Trees Forbs +#--- Canopy height (cm) parameters +# Canopy height is either constant through season or +# is a function of monthly biomass (g / m^2) + +# Grasses Shrubs Trees Forbs 300.0 0.0 0.0 300.0 # xinflec 29.5 5.0 5.0 29.5 # yinflec 85. 100. 3000. 85. # range @@ -20,29 +36,38 @@ 0.0 50. 1200. 0.0 # if > 0 then constant canopy height (cm) -# --- Vegetation interception parameters: kSmax * log10(1 + LAI_live + kdead * LAI_dead) -# Grasses Shrubs Trees Forbs - 1.0 2.6 2.0 1.0 # kSmax (mm) - 1.0 0.1 0.01 0.5 # kdead (0-1 fraction) +#--- Vegetation interception parameters +# Equation: kSmax * log10(1 + LAI_live + kdead * LAI_dead) + +# Grasses Shrubs Trees Forbs + 1.0 2.6 2.0 1.0 # kSmax (mm) + 1.0 0.1 0.01 0.5 # kdead (0-1 fraction) + +#--- Litter interception parameters +# Equation: kSmax * log10(1 + litter_density) -# --- Litter interception parameters: kSmax * log10(1 + litter_density) -# Grasses Shrubs Trees Forbs - 0.113 0.113 0.290 0.113 # kSmax (mm) +# Grasses Shrubs Trees Forbs + 0.113 0.113 0.290 0.113 # kSmax (mm) -# ---- Parameter for partitioning of bare-soil evaporation and transpiration as in Es = exp(-param*LAI) -# Grasses Shrubs Trees Forbs - 1. 1. 0.41 1. # Trees: According to a regression based on a review by Daikoku, K., S. Hattori, A. Deguchi, Y. Aoki, M. Miyashita, K. Matsumoto, J. Akiyama, S. Iida, T. Toba, Y. Fujita, and T. Ohta. 2008. Influence of evaporation from the forest floor on evapotranspiration from the dry canopy. Hydrological Processes 22:4083-4096. +#---- Parameter for partitioning of bare-soil evaporation and transpiration +# Equation: Es = exp(-param*LAI) +# Default value for trees derived from a regression based on data from a +# review by Daikoku et al. (2008) Hydrological Processes 22:4083-4096. +# Grasses Shrubs Trees Forbs + 1. 1. 0.41 1. -# ---- Parameter for scaling and limiting bare soil evaporation rate: if totagb (g/m2) > param then no bare-soil evaporation -# Grasses Shrubs Trees Forbs - 999. 999. 2099. 999. # +# --- Parameter for scaling and limiting bare soil evaporation rate +# If totagb (g / m2) > param then no bare-soil evaporation +# Grasses Shrubs Trees Forbs + 999. 999. 2099. 999. -# --- Shade effects on transpiration based on live and dead biomass -# Grasses Shrubs Trees Forbs + +#--- Shade effects on transpiration based on live and dead biomass +# Grasses Shrubs Trees Forbs 0.3 0.3 0.3 0.3 # shade scale 150. 150. 150. 150. # shade maximal dead biomass 300. 300. 0. 300. # tanfunc: xinflec @@ -51,37 +76,58 @@ 0.002 0.002 0.0002 0.002 # slope -# ---- Hydraulic redistribution: Ryel, Ryel R, Caldwell, Caldwell M, Yoder, Yoder C, Or, Or D, Leffler, Leffler A. 2002. Hydraulic redistribution in a stand of Artemisia tridentata: evaluation of benefits to transpiration assessed with a simulation model. Oecologia 130: 173-184. -# Grasses Shrubs Trees Forbs +#---- Hydraulic redistribution +# Implemenation based on Ryel et al. (2002) Oecologia 130: 173-184. +# Grasses Shrubs Trees Forbs 1 1 1 1 # flag to turn on/off (1/0) hydraulic redistribution -0.2328 -0.2328 -0.2328 -0.2328 # maxCondroot - maximum radial soil-root conductance of the entire active root system for water (cm/-bar/day) = 0.097 cm/MPa/h 10. 10. 10. 10. # swp50 - soil water potential (-bar) where conductance is reduced by 50% = -1. MPa 3.22 3.22 3.22 3.22 # shapeCond - shaping parameter for the empirical relationship from van Genuchten to model relative soil-root conductance for water -# ---- Critical soil water potential (MPa), i.e., when transpiration rates cannot sustained anymore, for instance, for many crop species -1.5 MPa is assumed and called wilting point -# Grasses Shrubs Trees Forbs +#---- Critical soil water potential (MPa) +# Soil water potential below which transpiration rates cannot be sustained, +# for instance, for many crop species -1.5 MPa is assumed (wilting point) + +# Grasses Shrubs Trees Forbs -3.5 -3.9 -2.0 -2.0 -# ---- CO2 Coefficients: multiplier = Coeff1 * x^Coeff2 -# Coefficients assume that monthly biomass inputs reflect values for conditions at -# 360 ppm CO2, i.e., multiplier = 1 for x = 360 ppm CO2 -# Grasses Shrubs Trees Forbs +#---- Effects of atmospheric CO2 concentrations +# Equation: multiplier = Coeff1 * x^Coeff2 +# Coefficients assume that monthly biomass inputs reflect values for conditions +# at 360 ppm CO2, i.e., multiplier = 1 for x = 360 ppm CO2 + +# Grasses Shrubs Trees Forbs 0.1319 0.1319 0.1319 0.1319 # Biomass Coeff1 0.3442 0.3442 0.3442 0.3442 # Biomass Coeff2 25.158 25.158 25.158 25.158 # WUE Coeff1 -0.548 -0.548 -0.548 -0.548 # WUE Coeff2 -# Grasslands component: -# -------------- Monthly production values ------------ +#------ Mean monthly biomass values +# Input biomass per unit area (g / m2) for each vegetation type represent +# values as if that vegetation type covers 100% of the simulated surface. +# That way input biomass values are independent of the input composition values. +# For example, +# - inputs for forbs: fCover = 0.4, biomass = 300 g/m2 +# - inputs for grasses: fCover = 0.6, biomass = 450 g/m2 +# Then, SOILWAT2 simulates a surface with vegetation of +# fCover = 1 (= 0.4 + 0.6) +# and a +# total biomass = 390 g / m2 (= 0.4 * 300 + 0.6 * 450) +# of which +# forb biomass = 120 g / m2 (0.4 * 300) +# and +# grass biomass = 270 g/m2 (= 0.6 * 450). + # Litter - dead leafy material on the ground (g/m^2 ). # Biomass - living and dead/woody aboveground standing biomass (g/m^2). # %Live - proportion of Biomass that is actually living (0-1.0). # LAI_conv - monthly amount of biomass needed to produce LAI=1.0 (g/m^2). # There should be 12 rows, one for each month, starting with January. -# + +# Grasslands component: #Litter Biomass %Live LAI_conv 75.0 150.0 0.00 300. # January 80.0 150.0 0.00 300. # February diff --git a/data-raw/1_Input/treatments/tr_siteparamin/siteparam.in b/data-raw/1_Input/treatments/tr_siteparamin/siteparam.in index a933074b..9a8fd022 100644 --- a/data-raw/1_Input/treatments/tr_siteparamin/siteparam.in +++ b/data-raw/1_Input/treatments/tr_siteparamin/siteparam.in @@ -1,82 +1,90 @@ -# ---- SWC limits ---- --1.0 # swc_min : cm/cm if 0 - <1.0, -bars if >= 1.0.; if < 0. then estimate residual water content for each layer -15.0 # swc_init: cm/cm if < 1.0, -bars if >= 1.0. -15.0 # swc_wet : cm/cm if < 1.0, -bars if >= 1.0. +#------ Input file for site location, initialization, and +# miscellaneous model parameters -# ---- Model flags and coefficients ---- -0 # reset (1/0): reset/don't reset swc each new year -1 # deepdrain (1/0): allow/disallow deep drainage function. - # if deepdrain == 1, model expects extra layer in soils file. -1.0 # multiplier for PET (eg for climate change). -0.0 #proportion of ponded surface water removed as daily runoff (value ranges between 0 and 1; 0=no loss of surface water, 1=all ponded water lost via runoff) -0.0 #proportion of water that arrives at surface added as daily runon [from a hypothetical identical neighboring site] (value ranges between 0 and +inf; 0=no runon, >0: runon is occuring) +# USER: The site location and the transpiration regions should +# be adjusted for site-specific run conditions. -# ---- Snow simulation parameters (SWAT2K model): Neitsch S, Arnold J, Kiniry J, Williams J. 2005. Soil and water assessment tool (SWAT) theoretical documentation. version 2005. Blackland Research Center, Texas Agricultural Experiment Station: Temple, TX. -# these parameters are RMSE optimized values for 10 random SNOTEL sites for western US -0.61 # TminAccu2 = Avg. air temp below which ppt is snow ( C) -1.54 # TmaxCrit = Snow temperature at which snow melt starts ( C) -0.1 # lambdasnow = Relative contribution of avg. air temperature to todays snow temperture vs. yesterday's snow temperature (0-1) -0.0 # RmeltMin = Minimum snow melt rate on winter solstice (cm/day/C) -0.27 # RmeltMax = Maximum snow melt rate on summer solstice (cm/day/C) +# USER: Most of the other values in this file are parameters that +# describe various model processes and should be considered fixed. -# ---- Drainage coefficient ---- -0.02 # slow-drain coefficient per layer (cm/day). See Eqn 2.9 in ELM doc. - # ELM shows this as a value for each layer, but this way it's applied to all. - # (Q=.02 in ELM doc, .06 in FORTRAN version). -# ---- Evaporation coefficients ---- +#---- Soil water content initialization, minimum, and wet condition +-1.0 # swc_min : cm/cm if 0 - <1.0, -bars if >= 1.0.; if < 0. then estimate residual water content for each layer +15.0 # swc_init: cm/cm if < 1.0, -bars if >= 1.0. +15.0 # swc_wet : cm/cm if < 1.0, -bars if >= 1.0. + +#---- Diffuse recharge and runoff/runon +0 # reset (1/0): do/don't reset soil water content for each year +1 # deepdrain (1/0): allow/disallow deep drainage (diffuse recharge) +1.0 # multiplier for PET (e.g., for climate change scenarios) +0.0 # proportion of ponded surface water removed as daily runoff (value ranges between 0 and 1; 0=no loss of surface water, 1=all ponded water lost via runoff) +0.0 # proportion of water that arrives at surface added as daily runon [from a hypothetical identical neighboring site] (value ranges between 0 and +inf; 0=no runon, >0: runon is occuring) + +#---- Snow simulation +# based on the SWAT2K model by Neitsch et al. (2005) +# Current values are RMSE optimized based on 10 random SNOTEL sites for western US +0.61 # TminAccu2 = Avg. air temp below which ppt is snow ( C) +1.54 # TmaxCrit = Snow temperature at which snow melt starts ( C) +0.1 # lambdasnow = Relative contribution of avg. air temperature to todays snow temperture vs. yesterday's snow temperature (0-1) +0.0 # RmeltMin = Minimum snow melt rate on winter solstice (cm/day/C) +0.27 # RmeltMax = Maximum snow melt rate on summer solstice (cm/day/C) + +#---- Hydraulic conductivity +0.02 # Parameter (cm / day) for unsaturated hydraulic conductivity, + # previously called slow-drain coefficient; See Eqn 2.9 in Parton 1978. + +#---- Evaporation # These control the tangent function (tanfunc) which affects the amount of soil -# water extractable by evaporation and transpiration. -# These constants aren't documented by the ELM doc. -45. # rate shift (x value of inflection point). lower value shifts curve - # leftward, meaning less water lost to evap at a given swp. effectively - # shortens/extends high rate. -.1 # rate slope: lower value (eg .01) straightens S shape meaning more gradual - # reduction effect; higher value (.5) makes abrupt transition -.25 # inflection point (y-value of inflection point) -0.5 # range: diff btw upper and lower rates at the limits +# water extractable by bare-soil evaporation and transpiration. +45. # rate shift (x value of inflection point). lower value shifts curve + # leftward, meaning less water lost to evap at a given swp. effectively + # shortens/extends high rate. +.1 # rate slope: lower value (eg .01) straightens S shape meaning more gradual + # reduction effect; higher value (.5) makes abrupt transition +.25 # inflection point (y-value of inflection point) +0.5 # range: diff btw upper and lower rates at the limits -# ---- Transpiration Coefficients ---- -# comments from Evap constants apply. -45. # rate shift -.1 # rate shape -.5 # inflection point -1.1 # range +#---- Transpiration +# These control the tangent function (tanfunc) which affects the amount of soil +# water extractable by transpiration. +45. # rate shift +.1 # rate shape +.5 # inflection point +1.1 # range -# ---- Intrinsic site params: -0.681 # latitude of the site in radians -1000 # elevation of site (m a.s.l.) -0 # slope at site (degrees): no slope = 0 --1 # aspect at site (degrees): N=0, E=90, S=180, W=270, no slope:-1 +#---- Site location and topography +0.681 # latitude of the site in radians +1000 # elevation of site (m a.s.l.) +0 # slope at site (degrees): no slope = 0 +-1 # aspect at site (degrees): N=0, E=90, S=180, W=270, no slope:-1 -# ---- Soil Temperature Constants ---- +#---- Soil temperature # from Parton 1978, ch. 2.2.2 Temperature-profile Submodel -300. # biomass limiter, 300 g/m^2 in Parton's equation for T1(avg daily temperature at the top of the soil) -15. # constant for T1 equation (used if biomass <= biomass limiter), 15 in Parton's equation --4. # constant for T1 equation (used if biomass > biomass limiter), -4 in Parton's equation -600. # constant for T1 equation (used if biomass > biomass limiter), 600 in Parton's equation -0.00070 # constant for cs (soil-thermal conductivity) equation, 0.00070 in Parton's equation -0.00030 # constant for cs equation, 0.00030 in Parton's equation -0.18 # constant for sh (specific heat capacity) equation, 0.18 in Parton's equation -4.15 # constant soil temperature (Celsius) at the lower boundary (max depth); approximate by mean annual air temperature of site -15. # deltaX parameter for soil_temperature function, default is 15. (distance between profile points in cm) max depth (the next number) should be evenly divisible by this number -990. # max depth for the soil_temperature function equation, default is 990. this number should be evenly divisible by deltaX -1 # flag, 1 to calculate soil_temperature, 0 to not calculate soil_temperature +300. # biomass limiter, 300 g/m^2 in Parton's equation for T1(avg daily temperature at the top of the soil) +15. # constant for T1 equation (used if biomass <= biomass limiter), 15 in Parton's equation +-4. # constant for T1 equation (used if biomass > biomass limiter), -4 in Parton's equation +600. # constant for T1 equation (used if biomass > biomass limiter), 600 in Parton's equation +0.00070 # constant for cs (soil-thermal conductivity) equation, 0.00070 in Parton's equation +0.00030 # constant for cs equation, 0.00030 in Parton's equation +0.18 # constant for sh (specific heat capacity) equation, 0.18 in Parton's equation +4.15 # constant soil temperature (Celsius) at the lower boundary (max depth); approximate by mean annual air temperature of site +15. # deltaX parameter for soil_temperature function, default is 15. (distance between profile points in cm) max depth (the next number) should be evenly divisible by this number +990. # max depth for the soil_temperature function equation, default is 990. this number should be evenly divisible by deltaX +1 # flag, 1 to calculate soil_temperature, 0 to not calculate soil_temperature # ---- CO2 Settings ---- -# Use biomass multiplier +# Activate (1) / deactivate (0) biomass multiplier 1 -# Use water-usage efficiency multiplier +# Activate (1) / deactivate (0) water-usage efficiency multiplier 1 -# Scenario +# Name of CO2 scenario: see input file `carbon.in` RCP85 -# ---- Transpiration regions ---- +#---- Transpiration regions # ndx : 1=shallow, 2=medium, 3=deep, 4=very deep -# layer: deepest layer number of the region. -# Layers are defined in soils.in. -# ndx layer - 1 3 - 2 5 - 3 8 -# 4 20 +# layer: deepest soil layer number of the region. +# Must agree with soil layers as defined in `soils.in` +# ndx layer + 1 3 + 2 5 + 3 8 diff --git a/data-raw/1_Input/treatments/tr_soilsin/soils.in b/data-raw/1_Input/treatments/tr_soilsin/soils.in index 088f502d..30f22de6 100644 --- a/data-raw/1_Input/treatments/tr_soilsin/soils.in +++ b/data-raw/1_Input/treatments/tr_soilsin/soils.in @@ -1,24 +1,31 @@ -# Soil layer definitions -# Location: -# -# depth = (cm) lower limit of layer; layers must be in order of depth. -# matricd = (g/cm^3) bulk density of soil in this layer. -# gravel_content = the percent volume of each layer composed of gravel (i.e., particles > 2mm) -# evco = (frac) proportion of total baresoil evap from this layer. -# trco = (frac) proportion of total transpiration from this layer for each vegetation type (tree, forb, shrub, grass) -# %sand = (frac) proportion of sand in layer (0-1.0). -# %clay = (frac) proportion of clay in layer (0-1.0). -# imperm = (frac) proportion of 'impermeability' to water percolation(/infiltration/drainage) in layer (0-1.0) -# soiltemp = the initial temperature of each soil layer (in celcius), from the day before the simulation starts -# Note that the evco and trco columns must sum to 1.0 or they will -# be normalized. -# +#------ Input for soil information: soil layer, soil texture, etc. + +# A table with up to `MAX_LAYERS` rows (soil layers) and 12 columns: +# - depth = (cm) lower limit of layer; layers must be in order of depth +# - matricd = (g / cm^3) soil bulk density +# - gravel_content = (frac, 0-1) proportion of gravel by volume +# (i.e., particles > 2mm) +# - evco = (frac, 0-1) proportion of potential bare soil evaporation +# - trco = (frac, 0-1) proportion of potential transpiration for each +# vegetation type (tree, forb, shrub, grass), +# e.g., estimated as proportion of active roots +# - %sand = (frac, 0-1) proportion of sand by weight +# - %clay = (frac, 0-1) proportion of clay by weight +# - imperm = (frac, 0-1) proportion of 'impermeability' to water +# percolation(/infiltration/drainage) +# - soiltemp = (C) initial temperature + +# USER: the evco and trco columns must sum to 1.0 or they will be normalized. + +# The minimum number of soil layers is 1 and the maximum number is `MAX_LAYERS` +# which is defined in `SW_Defines.h`. + # depth matricd gravel_content evco trco_grass trco_shrub trco_tree trco_forb %sand %clay imperm soiltemp - 5.000 1.430 0.100 0.813 0.0496 0.134 0.0496 0.134 0.510 0.150 0.000 -1.000 - 10.000 1.410 0.100 0.153 0.0495 0.094 0.0495 0.094 0.440 0.260 0.000 -1.000 - 20.000 1.390 0.100 0.034 0.1006 0.176 0.1006 0.176 0.350 0.410 0.000 -1.000 - 30.000 1.390 0.100 0.000 0.1006 0.175 0.1006 0.175 0.320 0.450 0.000 -1.000 - 40.000 1.380 0.200 0.000 0.1006 0.110 0.1006 0.110 0.310 0.470 0.000 0.000 - 60.000 1.150 0.200 0.000 0.1997 0.109 0.1997 0.109 0.320 0.470 0.000 0.000 - 80.000 1.310 0.200 0.000 0.1997 0.101 0.1997 0.101 0.570 0.280 0.000 1.000 -100.000 1.310 0.200 0.000 0.1997 0.101 0.1997 0.101 0.570 0.280 0.000 1.000 + 5.0 1.430 0.100 0.813 0.0496 0.134 0.0496 0.134 0.510 0.150 0.000 -1.000 + 10.0 1.410 0.100 0.153 0.0495 0.094 0.0495 0.094 0.440 0.260 0.000 -1.000 + 20.0 1.390 0.100 0.034 0.1006 0.176 0.1006 0.176 0.350 0.410 0.000 -1.000 + 30.0 1.390 0.100 0.000 0.1006 0.175 0.1006 0.175 0.320 0.450 0.000 -1.000 + 40.0 1.380 0.200 0.000 0.1006 0.110 0.1006 0.110 0.310 0.470 0.000 0.000 + 60.0 1.150 0.200 0.000 0.1997 0.109 0.1997 0.109 0.320 0.470 0.000 0.000 + 80.0 1.310 0.200 0.000 0.1997 0.101 0.1997 0.101 0.570 0.280 0.000 1.000 +100.0 1.310 0.200 0.000 0.1997 0.101 0.1997 0.101 0.570 0.280 0.000 1.000 diff --git a/data-raw/1_Input/treatments/tr_weathersetupin/weathsetup.in b/data-raw/1_Input/treatments/tr_weathersetupin/weathsetup.in index 1d74f9f6..45b7787d 100755 --- a/data-raw/1_Input/treatments/tr_weathersetupin/weathsetup.in +++ b/data-raw/1_Input/treatments/tr_weathersetupin/weathsetup.in @@ -1,13 +1,20 @@ -# Weather setup parameters -# -1 # 1 = simulate snow processes; 0 = no snow effects -0.0 # % of snow drift per snow event (+ indicates snow addition, - indicates snow taken away from site) -0.0 # % of snowmelt water as runoff/on per event (>0 indicates runoff, <0 indicates runon) +#------ Input file for weather-related parameters and weather generator settings + +#--- Activate/deactivate simulation of snow-related processes +1 # 1 = do/don't simulate snow processes +0.0 # snow drift/blowing snow (% per snow event): > 0 is adding snow, < 0 is removing snow +0.0 # runoff/runon of snowmelt water (% per snowmelt event): > 0 is runoff, < 0 is runon + + +#--- Activate/deactivate weather generator / historical daily weather inputs 0 # 0 = use historical data only; 1 = use markov process for missing weather -1980 # first year to begin historical weather. -5 # number of days to use in the running average of temperature. +1980 # first year to begin historical weather + # (filename, e.g., Input/data_weather/weath.1949; see `files.in` for + # relative pathname and basis of filename) +5 # number of days to use in a moving average of temperature + -# Monthly scaling parameters: +#--- Monthly scaling parameters: # Month 1 = January, Month 2 = February, etc. # PPT = multiplicative for daily PPT; max(0, scale * ppt) # MaxT = additive for daily max temperature [C]; scale + maxtemp