Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Development for v6.2.0 #248

Merged
merged 15 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
^cran-comments\.md$
^NEWS\.md$
^tests/
tests/rSOILWAT_IntegrationTestOutput
tests/rSOILWAT_IntegrationTestOutput*
src/SOILWAT2/\.git
src/SOILWAT2/\.github
src/SOILWAT2/doc
Expand Down
9 changes: 6 additions & 3 deletions .github/workflows/check-standard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ on:
pull_request:
branches: [main, release/**]

name: R-CMD-check
name: R-CMD-check.yml

permissions: read-all

jobs:
R-CMD-check:
Expand All @@ -33,7 +35,7 @@ jobs:
fail-fast: false
matrix:
config:
- {os: macOS-latest, r: 'release'}
- {os: macos-latest, r: 'release'}
- {os: windows-latest, r: 'release'}
- {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'}
- {os: ubuntu-latest, r: 'release'}
Expand All @@ -45,7 +47,7 @@ jobs:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: recursive

Expand All @@ -72,4 +74,5 @@ jobs:
with:
upload-snapshots: true
error-on: '"error"'
build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")'

2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Thumbs.db
# Package check files
..Rcheck
rSOILWAT2.Rcheck
rSOILWAT_IntegrationTestOutput/
rSOILWAT_IntegrationTestOutput*
tests/spelling.Rout.save
backup/

Expand Down
2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[submodule "src/SOILWAT2"]
path = src/SOILWAT2
url = https://github.com/DrylandEcology/SOILWAT2
branch = master
branch = master
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Package: rSOILWAT2
Version: 6.1.0
Version: 6.2.0
Title: An Ecohydrological Ecosystem-Scale Water Balance Simulation Model
Description: Access to the C-based SOILWAT2 v8.0.0 and functionality for
Description: Access to the C-based SOILWAT2 v8.0.1 and functionality for
SQLite-database of weather data.
Authors@R: c(
person(
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ export(swrc_vwc_to_swp)
export(time_columns)
export(update_biomass)
export(update_requested_years)
export(upgrade_weatherColumns)
export(upgrade_weatherDF)
export(upgrade_weatherHistory)
export(weatherGenerator_dataColumns)
Expand Down
20 changes: 19 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
# rSOILWAT2 v6.1.0-9000
# rSOILWAT2 v6.2.0
* Simulation output remains the same as the previous version unless
relative humidity is calculated from vapor pressure or specific humidity.
* Update `SOILWAT2` to v8.0.1 which fixed the calculation of relative humidity
and the count of days where missing weather was imputed by `"LOCF"`.

## New features
* `validObject()` method for class `"swInputData"` now includes checks for a
valid `"weatherHistory"` object.

## Bugfix
* `dbW_fixWeather()` now handles data objects with all missing values.

## Changes to interface
* The inputs of daily specific humidity changed units (`"%"` to `"g kg-1"`)
and name (`"specHavg_pct"` to `"specHavg_gPERkg"`).


# rSOILWAT2 v6.1.0
* This version produces the same output as the previous version.
* `SOILWAT2` updated to v8.0.0 which now includes a simulation domain;
however, this has no impact on `rSOILWAT2`.
Expand Down
12 changes: 12 additions & 0 deletions R/A_swGenericMethods.R
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@ format_timestamp <- function(object) {
#'
#' @section Details:
#' List of changes:
#' * Changes with `v6.2.0`:
#' * class [`swWeatherData`]: slot `"data"` changed column name
#' (`"specHavg_pct"` to `"specHavg_gPERkg"`) and
#' units (`"%"` to `"g kg-1"`).
#' * Changes with `v6.1.0`:
#' * class [`swInputData-class`]:
#' new slot `"spinup"` of new class [`swSpinup-class`]
Expand All @@ -220,6 +224,14 @@ format_timestamp <- function(object) {
#' * class [`swFiles-class`]:
#' `SWRC` parameter input file added as file 6 for a new total of 23
#' * class [`swProd-class`]: new slot `"veg_method"`
#' * class [`swWeatherData`]: new slots `"use_cloudCoverMonthly"`,
#' `"use_windSpeedMonthly"`, `"use_humidityMonthly"`,
#' `"dailyInputFlags"`, and `"desc_rsds"`
#' * class [`swWeatherData`]: slot `"data"` gained 11 new columns:
#' `"cloudCov_pct"`, `"windSpeed_mPERs"`, `"windSpeed_east_mPERs"`,
#' `"windSpeed_north_mPERs"`, `"rHavg_pct"`, `"rHmax_pct"`,
#' `"rHmin_pct"`, `"specHavg_pct"`, `"Tdewpoint_C"`, `"actVP_kPa"`,
#' and `"shortWR"`
#' * Changes with `v5.4.0`:
#' * classes [`swEstabSpecies-class`] and [`swEstab-class`]:
#' new slot `"vegType"`
Expand Down
97 changes: 93 additions & 4 deletions R/D_swWeatherData.R
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,28 @@
"Tmax_C", "Tmin_C", "PPT_cm",
"cloudCov_pct",
"windSpeed_mPERs", "windSpeed_east_mPERs", "windSpeed_north_mPERs",
"rHavg_pct", "rHmax_pct", "rHmin_pct", "specHavg_pct", "Tdewpoint_C",
"rHavg_pct", "rHmax_pct", "rHmin_pct", "specHavg_gPERkg", "Tdewpoint_C",
"actVP_kPa",
"shortWR"
)
}

#' @return A data frame with four columns:
#' * `"old"`: the outdated weather data column name
#' * `"new"`: the new weather data column name
#' * `"v"`: the `"rSOILWAT2"` version when the name change was introduced
#' * `"fail"`: error if non-missing values are present
#' @md
#' @noRd
weather_renamedDataColumns <- function() {
rbind(
data.frame(
old = "specHavg_pct", new = "specHavg_gPERkg", v = "6.2.0", fail = TRUE,
stringsAsFactors = FALSE
)
)
}

#' Functions to summarize currently implemented daily weather variables
#' @return A named vector of functions that summarize
#' daily weather variables across time.
Expand All @@ -54,7 +70,8 @@
rHavg_pct = mean,
rHmax_pct = mean,
rHmin_pct = mean,
specHavg_pct = mean,
specHavg_pct = mean, # specific humidity: rSOILWAT2 v6.0.0 - v6.1.0
specHavg_gPERkg = mean, # specific humidity: rSOILWAT2 >= v6.1.1
Tdewpoint_C = mean,
actVP_kPa = mean,
shortWR = mean
Expand Down Expand Up @@ -89,7 +106,7 @@
#' \var{windSpeed_mPERs},
#' \var{windSpeed_east_mPERs}, \var{windSpeed_north_mPERs},
#' \var{rHavg_pct}, \var{rHmax_pct}, \var{rHmin_pct},
#' \var{specHavg_pct}, \var{Tdewpoint_C},
#' \var{specHavg_gPERkg}, \var{Tdewpoint_C},
#' \var{actVP_kPa}, and
#' \var{shortWR}.
#'
Expand Down Expand Up @@ -156,13 +173,28 @@
}

tmp <- dim(object@data)
if (tmp[2] != ncol(ref@data)) {
if (tmp[[2L]] != ncol(ref@data)) {
msg <- paste(
"@data must have exactly", ncol(ref@data), "columns corresponding to",
toString(colnames(ref@data))
)
val <- if (isTRUE(val)) msg else c(val, msg)
}

cns <- colnames(object@data)
validCns <- c("day", colnames(ref@data))
if (!all(tolower(cns) %in% tolower(validCns))) {
shouldNot <- setdiff(tolower(cns), tolower(validCns))
shouldHave <- setdiff(tolower(colnames(ref@data)), tolower(cns))
msg <- paste(
"@data has column(s)",
toString(shQuote(cns[tolower(cns) %in% shouldNot])),
"instead of",
toString(shQuote(validCns[tolower(validCns) %in% shouldHave]))
)
val <- if (isTRUE(val)) msg else c(val, msg)
}

if (!(tmp[1] %in% c(365, 366))) {
msg <- "@data must 365 or 366 rows corresponding to day of year."
val <- if (isTRUE(val)) msg else c(val, msg)
Expand Down Expand Up @@ -198,16 +230,62 @@
do.call("new", args = c("swWeatherData", dots[dns %in% sns]))
}


#' @param weatherDF A data frame with weather variables.
#' @param template_weatherColumns A vector with requested weather variables.
#'
#' @return For [upgrade_weatherColumns()]:
#' an updated `weatherDF` with requested column name changes.
#'
#' @examples
#' upgrade_weatherColumns(
#' data.frame(DOY = 1:2, Tmax_C = runif(2), dummy = runif(2))
#' )
#' upgrade_weatherColumns(
#' data.frame(DOY = 1:2, Tmax_C = runif(2), specHavg_pct = NA)
#' )
#'
#' @md
#' @rdname sw_upgrade
#' @export
upgrade_weatherColumns <- function(
weatherDF,
template_weatherColumns = c("Year", "DOY", weather_dataColumns())
) {
cns <- colnames(weatherDF)
if (!all(cns %in% template_weatherColumns)) {
rds <- weather_renamedDataColumns()
ids <- match(cns, rds[, "old", drop = TRUE], nomatch = 0L)
for (k in which(ids > 0L)) {
if (
isTRUE(rds[ids[[k]], "fail", drop = TRUE]) &&
!all(is_missing_weather(weatherDF[, cns[[k]], drop = TRUE]))
) {
stop(
"Renaming ", shQuote(cns[[k]]), " to ",
shQuote(as.character(rds[ids[[k]], "new", drop = TRUE])),
" failed because of non-missing values."
)
}

cns[[k]] <- as.character(rds[ids[[k]], "new", drop = TRUE])
}
colnames(weatherDF) <- cns
}

weatherDF
}

#' @return For [upgrade_weatherDF()]:
#' an updated `weatherDF` with requested columns.
#'
#' @examples
#' upgrade_weatherDF(
#' data.frame(DOY = 1:2, Tmax_C = runif(2), dummy = runif(2))
#' )
#' upgrade_weatherDF(
#' data.frame(DOY = 1:2, Tmax_C = runif(2), specHavg_pct = NA)
#' )
#'
#' @md
#' @rdname sw_upgrade
Expand All @@ -223,6 +301,8 @@
)
)

weatherDF <- upgrade_weatherColumns(weatherDF)

cns <- intersect(template_weatherColumns, colnames(weatherDF))
if (length(cns) < 1L) stop("Required weather variables not found.")
template_data[, cns] <- weatherDF[, cns]
Expand Down Expand Up @@ -275,6 +355,15 @@
}
}

validObject_weatherHistory <- function(object) {
res <- lapply(object, validObject)
has_msg <- vapply(res, is.character, FUN.VALUE = NA)
if (any(has_msg)) {
unlist(res[has_msg])

Check warning on line 362 in R/D_swWeatherData.R

View check run for this annotation

Codecov / codecov/patch

R/D_swWeatherData.R#L362

Added line #L362 was not covered by tests
} else {
TRUE
}
}

#' @rdname swWeatherData-class
#' @export
Expand Down
12 changes: 11 additions & 1 deletion R/K_swContainer.R
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,17 @@ swInputData <- function(...) {
setValidity(
"swInputData",
function(object) {
res <- lapply(slotNames(object), function(sn) validObject(slot(object, sn)))
res <- lapply(
slotNames(object),
function(sn) {
if (identical(sn, "weatherHistory")) {
validObject_weatherHistory(slot(object, sn))
} else {
validObject(slot(object, sn))
}
}
)

has_msg <- sapply(res, is.character)
if (any(has_msg)) {
unlist(res[has_msg])
Expand Down
25 changes: 17 additions & 8 deletions R/swWeatherGenerator.R
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,9 @@ compare_weather <- function(
#' @inheritParams sw_weather_data
#' @param years An integer vector. The calendar years for which to generate
#' daily weather. If `NULL`, then extracted from `weatherData`.
#' @param elevation A numeric value. Site elevation above sea level `[m]`.
#' Used only if specific humidity is provided as input
#' for calculating relative humidity.
#' @param wgen_coeffs A list with two named elements `"mkv_doy"` and
#' `"mkv_woy"`, i.e., the return value of [dbW_estimate_WGen_coefs()].
#' If `NULL`, then [dbW_estimate_WGen_coefs()] is called on `weatherData`.
Expand Down Expand Up @@ -1210,6 +1213,7 @@ compare_weather <- function(
dbW_generateWeather <- function(
weatherData,
years = NULL,
elevation = NA,
wgen_coeffs = NULL,
imputation_type = "mean",
imputation_span = 5L,
Expand Down Expand Up @@ -1243,6 +1247,9 @@ dbW_generateWeather <- function(
swYears_EndYear(sw_in) <- max(years)
swYears_StartYear(sw_in) <- min(years)

# Set elevation
swSite_IntrinsicSiteParams(sw_in)[3L] <- as.numeric(elevation)

# Turn on weather generator (to fill in missing values)
swWeather_UseMarkov(sw_in) <- TRUE
swWeather_UseMarkovOnly(sw_in) <- FALSE
Expand Down Expand Up @@ -1371,6 +1378,7 @@ dbW_imputeWeather <- function(
seed = NULL,
method_after_wg = c("interp", "locf", "mean", "none", "fail"),
nmax_run = Inf,
elevation = NA,
return_weatherDF = FALSE
) {

Expand Down Expand Up @@ -1402,6 +1410,7 @@ dbW_imputeWeather <- function(
#--- Use weather generator for available variables
tmp <- dbW_generateWeather(
weatherData = weatherData,
elevation = elevation,
return_weatherDF = TRUE,
seed = seed
)
Expand Down Expand Up @@ -1717,16 +1726,16 @@ dbW_fixWeather <- function(
tmp <- which(rowSums(!is_miss1) > 0L)
ids <- tmp[c(1L, length(tmp))]

ids_startend <-
ids_startend <- if (length(tmp) > 0L) {
# before start
(weatherData1[["Year"]] < weatherData1[ids[[1L]], "Year"]) |
(weatherData1[["Year"]] == weatherData1[ids[[1L]], "Year"] &
weatherData1[["DOY"]] < weatherData1[ids[[1L]], "DOY"]) |
# after end
(weatherData1[["Year"]] == weatherData1[ids[[2L]], "Year"] &
weatherData1[["DOY"]] > weatherData1[ids[[2L]], "DOY"]) |
(weatherData1[["Year"]] > weatherData1[ids[[2L]], "Year"])

(weatherData1[["Year"]] == weatherData1[ids[[1L]], "Year"] &
weatherData1[["DOY"]] < weatherData1[ids[[1L]], "DOY"]) |
# after end
(weatherData1[["Year"]] == weatherData1[ids[[2L]], "Year"] &
weatherData1[["DOY"]] > weatherData1[ids[[2L]], "DOY"]) |
(weatherData1[["Year"]] > weatherData1[ids[[2L]], "Year"])
}


#--- Interpolate short missing runs
Expand Down
Loading
Loading