From 839b17ebe820ffe621e17eb2a69242ed53e7cb79 Mon Sep 17 00:00:00 2001 From: anshul23102 Date: Sat, 16 May 2026 06:47:17 +0530 Subject: [PATCH 1/4] fix(utils): accept NULL as synonym for NA in read.output start/end year Fixes #3864. Previously start.year and end.year used NA as the sentinel for 'read all years', while variables, ncfiles, and pft.name used NULL. This inconsistency made the API confusing. Now NULL is silently converted to NA at the top of read.output(), so both sentinels work. Default values and existing behavior are unchanged. Adds a test confirming NULL and NA produce identical results. --- base/utils/R/read.output.R | 7 ++++++- base/utils/tests/testthat/test-read.output.R | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/base/utils/R/read.output.R b/base/utils/R/read.output.R index d26449297e0..28c29478cea 100644 --- a/base/utils/R/read.output.R +++ b/base/utils/R/read.output.R @@ -40,7 +40,7 @@ #' print a summary of the means of each variable for each year. #' @param start.year,end.year first and last year of output to read. #' Specify as a date-time (only the year portion is used) or as a -#' four-digit number or string. If `NA`, reads all years found in +#' four-digit number or string. If `NA` or `NULL`, reads all years found in #' `outdir`. #' @return If `dataframe = FALSE`, a vector of output variables. If #' `dataframe = TRUE`, a `data.frame` of output variables with @@ -63,6 +63,11 @@ read.output <- function(runid, outdir, ## cflux = c('GPP', 'NPP', 'NEE', 'TotalResp', 'AutoResp', 'HeteroResp', 'DOC_flux', 'Fire_flux') # kgC m-2 s-1 ## wflux = c('Evap', 'TVeg', 'Qs', 'Qsb', 'Rainf') # kgH20 m-2 d-1 + # Accept NULL as a synonym for NA for start.year and end.year, + # consistent with how other params (variables, ncfiles, pft.name) signal "use all" + if (is.null(start.year)) start.year <- NA + if (is.null(end.year)) end.year <- NA + if ((missing(runid) || missing(outdir)) && is.null(ncfiles)) { PEcAn.logger::logger.severe( "`runid` or `outdir` is missing, and `ncfiles` is NULL.", diff --git a/base/utils/tests/testthat/test-read.output.R b/base/utils/tests/testthat/test-read.output.R index 00a805311c5..216d649f022 100644 --- a/base/utils/tests/testthat/test-read.output.R +++ b/base/utils/tests/testthat/test-read.output.R @@ -57,6 +57,20 @@ test_that("accepts start and end years as string, number, datetime", { expect_length(res_end[["posix"]], 365 * 2) }) +test_that("accepts NULL as synonym for NA in start.year and end.year", { + times_to_netcdf(0:364, "days since 2001-01-01", testdir, "2001.nc") + times_to_netcdf(0:364, "days since 2002-01-01", testdir, "2002.nc") + + out_log <- capture.output(type = "message", { + res_na <- read.output(runid = "", outdir = testdir, variables = "Y", + start.year = NA, end.year = NA, dataframe = TRUE) + res_null <- read.output(runid = "", outdir = testdir, variables = "Y", + start.year = NULL, end.year = NULL, dataframe = TRUE) + }) + expect_equivalent(res_na, res_null) + expect_length(res_null$posix, 365 * 2) +}) + test_that("handles arbitrary time offsets", { times_to_netcdf(365:730, "days since 2003-01-01", testdir, "2004.nc") times_to_netcdf( ((0:364)+916) * 24, "hours since 2002-06-30", testdir, "2005.nc") From 3457c2e30d8ca5d4bd3bfb1f246a277a8415c729 Mon Sep 17 00:00:00 2001 From: anshul23102 Date: Sat, 16 May 2026 06:56:33 +0530 Subject: [PATCH 2/4] fix(test): use isolated tempdir in NULL year synonym test The shared testdir accumulates files from previous tests, causing the year count assertion to fail. Use a fresh local_tempdir() so the test only sees exactly the two years it creates. --- base/utils/tests/testthat/test-read.output.R | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/base/utils/tests/testthat/test-read.output.R b/base/utils/tests/testthat/test-read.output.R index 216d649f022..4fcc8667dc9 100644 --- a/base/utils/tests/testthat/test-read.output.R +++ b/base/utils/tests/testthat/test-read.output.R @@ -58,13 +58,14 @@ test_that("accepts start and end years as string, number, datetime", { }) test_that("accepts NULL as synonym for NA in start.year and end.year", { - times_to_netcdf(0:364, "days since 2001-01-01", testdir, "2001.nc") - times_to_netcdf(0:364, "days since 2002-01-01", testdir, "2002.nc") + nulldir <- withr::local_tempdir() + times_to_netcdf(0:364, "days since 2001-01-01", nulldir, "2001.nc") + times_to_netcdf(0:364, "days since 2002-01-01", nulldir, "2002.nc") out_log <- capture.output(type = "message", { - res_na <- read.output(runid = "", outdir = testdir, variables = "Y", + res_na <- read.output(runid = "", outdir = nulldir, variables = "Y", start.year = NA, end.year = NA, dataframe = TRUE) - res_null <- read.output(runid = "", outdir = testdir, variables = "Y", + res_null <- read.output(runid = "", outdir = nulldir, variables = "Y", start.year = NULL, end.year = NULL, dataframe = TRUE) }) expect_equivalent(res_na, res_null) From 5bc385cd819af79f7491c7c435834b089e0d8dd8 Mon Sep 17 00:00:00 2001 From: anshul23102 Date: Sat, 16 May 2026 07:25:39 +0530 Subject: [PATCH 3/4] Sync read.output.Rd with updated roxygen docs Regenerates the man page to reflect the NA/NULL synonym note added to the start.year/end.year parameter documentation. --- base/utils/man/read.output.Rd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/utils/man/read.output.Rd b/base/utils/man/read.output.Rd index efc77553a27..6a5b74f912d 100644 --- a/base/utils/man/read.output.Rd +++ b/base/utils/man/read.output.Rd @@ -26,7 +26,7 @@ Can be omitted if \code{ncfiles} is set.} \item{start.year, end.year}{first and last year of output to read. Specify as a date-time (only the year portion is used) or as a -four-digit number or string. If \code{NA}, reads all years found in +four-digit number or string. If \code{NA} or \code{NULL}, reads all years found in \code{outdir}.} \item{variables}{Character vector of variables to be read from From 063d9c58fccafb8e8639877d1715bfbb921f1ede Mon Sep 17 00:00:00 2001 From: anshul23102 Date: Sat, 16 May 2026 12:46:06 +0530 Subject: [PATCH 4/4] Default start.year/end.year to NULL; simplify docs Per infotroph review: change defaults from NA to NULL so the interface is consistent with other "use all" parameters (variables, ncfiles, pft.name). Both NULL and NA continue to work identically. Update docs to advertise NULL as the canonical sentinel, and add a NEWS.md entry. --- base/utils/NEWS.md | 4 ++++ base/utils/R/read.output.R | 6 +++--- base/utils/man/read.output.Rd | 6 +++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/base/utils/NEWS.md b/base/utils/NEWS.md index e6effc30eed..c5fd5c16754 100644 --- a/base/utils/NEWS.md +++ b/base/utils/NEWS.md @@ -1,5 +1,9 @@ # PEcAn.utils 1.8.2 +## Changed + +* `read.output()`: `start.year` and `end.year` now default to `NULL` (read all years) instead of `NA`, and both `NULL` and `NA` are accepted as "read all years" sentinels (#3987). + ## Added * New function `nc_write_varfiles()` creates text summaries of the variables in all netCDF files in an output directory, writing either one file named `nc_vars.txt` if `output_mode = "combined"` or a separate `[filename].nc.var` alongside each netCDF if `output_mode = "paired"` (#3611). diff --git a/base/utils/R/read.output.R b/base/utils/R/read.output.R index 28c29478cea..db72e7658cd 100644 --- a/base/utils/R/read.output.R +++ b/base/utils/R/read.output.R @@ -40,7 +40,7 @@ #' print a summary of the means of each variable for each year. #' @param start.year,end.year first and last year of output to read. #' Specify as a date-time (only the year portion is used) or as a -#' four-digit number or string. If `NA` or `NULL`, reads all years found in +#' four-digit number or string. If `NULL`, reads all years found in #' `outdir`. #' @return If `dataframe = FALSE`, a vector of output variables. If #' `dataframe = TRUE`, a `data.frame` of output variables with @@ -50,8 +50,8 @@ #' @export #' @author Michael Dietze, David LeBauer, Alexey Shiklomanov read.output <- function(runid, outdir, - start.year = NA, - end.year = NA, + start.year = NULL, + end.year = NULL, variables = "GPP", dataframe = FALSE, pft.name = NULL, diff --git a/base/utils/man/read.output.Rd b/base/utils/man/read.output.Rd index 6a5b74f912d..00deaf428f0 100644 --- a/base/utils/man/read.output.Rd +++ b/base/utils/man/read.output.Rd @@ -7,8 +7,8 @@ read.output( runid, outdir, - start.year = NA, - end.year = NA, + start.year = NULL, + end.year = NULL, variables = "GPP", dataframe = FALSE, pft.name = NULL, @@ -26,7 +26,7 @@ Can be omitted if \code{ncfiles} is set.} \item{start.year, end.year}{first and last year of output to read. Specify as a date-time (only the year portion is used) or as a -four-digit number or string. If \code{NA} or \code{NULL}, reads all years found in +four-digit number or string. If \code{NULL}, reads all years found in \code{outdir}.} \item{variables}{Character vector of variables to be read from