Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
20 changes: 18 additions & 2 deletions models/sipnet/R/model2netcdf.SIPNET.R
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,15 @@ model2netcdf.SIPNET <- function(outdir, sitelat, sitelon, start_date, end_date,
output[["coarse_root_carbon_content"]] <- sub.sipnet.output$coarseRootC * 0.001 ## coarse_root_carbon_content kgC/m2
output[["GWBI"]] <- (sub.sipnet.output$woodCreation * 0.001) / 86400 ## kgC/m2/s - this is daily in SIPNET
output[["AGB"]] <- (sub.sipnet.output$plantWoodC + sub.sipnet.output$plantLeafC) * 0.001 # Total aboveground biomass kgC/m2
# columns only present in sipnet >= v2 with N and methane turned on
if ("n2o" %in% names(sub.sipnet.output)) {
output[["N2O_flux"]] <- (sub.sipnet.output$n2o * 0.001) / timestep.s
# convert g N m-2 per timestep -> kg N m-2 s-1
}
if ("ch4" %in% names(sub.sipnet.output)) {
output[["CH4_flux"]] <- (sub.sipnet.output$ch4 * 0.001) / timestep.s
# convert g C m-2 per timestep -> kg C m-2 s-1
}
output[["time_bounds"]] <- c(rbind(bounds[,1], bounds[,2]))

# ******************** Declare netCDF variables ********************#
Expand Down Expand Up @@ -236,6 +245,13 @@ model2netcdf.SIPNET <- function(outdir, sitelat, sitelon, start_date, end_date,
longname = "history time interval endpoints", dim=list(time_interval,time = t),
prec = "double")
)

if ("N2O_flux" %in% names(output)) {
nc_var[["N2O_flux"]] <- PEcAn.utils::to_ncvar("N2O_flux", dims)
}
if ("CH4_flux" %in% names(output)) {
nc_var[["CH4_flux"]] <- PEcAn.utils::to_ncvar("CH4_flux", dims)
}

# ******************** Create netCDF and output variables ********************#
### Output netCDF data
Expand Down Expand Up @@ -264,8 +280,8 @@ model2netcdf.SIPNET <- function(outdir, sitelat, sitelon, start_date, end_date,
}else{
nc <- ncdf4::nc_create(file.path(outdir, paste(y, "nc", sep = ".")), nc_var)
ncdf4::ncatt_put(nc, "time", "bounds", "time_bounds", prec=NA)
for (i in seq_along(nc_var)) {
ncdf4::ncvar_put(nc, nc_var[[i]], output[[i]])
for (key in names(nc_var)) {
ncdf4::ncvar_put(nc, nc_var[[key]], output[[key]])
}
ncdf4::nc_close(nc)
}
Expand Down
102 changes: 102 additions & 0 deletions models/sipnet/tests/testthat/test-model2netcdf.SIPNET.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
setup_sipnet_test <- function(sipnet_dat, delete.raw = FALSE) {
base <- withr::local_tempdir(pattern = "sipnet_test_", .local_envir = parent.frame())
outdir <- file.path(base, "out", "run1")
rundir <- file.path(base, "run", "run1")
dir.create(outdir, recursive = TRUE)
dir.create(rundir, recursive = TRUE)

writeLines(
c("plantWoodInit\t30000",
"leafCSpWt\t32"),
file.path(rundir, "sipnet.param")
)

out_path <- file.path(outdir, "sipnet.out")
writeLines("Notes: units in g/m2 per timestep; water in cm", out_path)
write.table(sipnet_dat, file = out_path, append = TRUE,
row.names = FALSE, quote = FALSE, sep = "\t")


model2netcdf.SIPNET(
outdir = outdir,
sitelat = 38.0,
sitelon = -121.0,
start_date = "2002-01-01",
end_date = "2002-12-31",
delete.raw = delete.raw,
revision = "r136"
)

list(outdir = outdir, rundir = rundir, out_path = out_path)
}

make_base_sipnet <- function(n = 4L) {
data.frame(
year = 2002,
day = rep(c(1, 2), each = n / 2, length.out = n),
time = rep(c(6, 18), length.out = n),
plantWoodC = 5000, plantLeafC = 200, woodCreation = 0.5,
soil = 10000, microbeC = 8, coarseRootC = 1200, fineRootC = 800,
litter = 400, soilWater = 14, soilWetnessFrac = 0.85, snow = 0,
npp = 0.05, nee = 0.10, cumNEE = cumsum(rep(0.1, n)),
gpp = 0.30, rAboveground = 0.04, rSoil = 0.09, rRoot = 0.01,
ra = 0.05, rh = 0.08, rtot = 0.13,
evapotranspiration = 0.005, fluxestranspiration = 0.003
)
}


test_that("model2netcdf.SIPNET converts v2 output including N2O and CH4 fluxes", {
n <- 4L
ts_s <- 43200
sipnet_dat <- make_base_sipnet(n)
sipnet_dat$n2o <- 0.002
sipnet_dat$ch4 <- 0.001
paths <- setup_sipnet_test(sipnet_dat)
nc_file <- file.path(paths$outdir, "2002.nc")
expect_true(file.exists(nc_file))

nc <- ncdf4::nc_open(nc_file)
on.exit(ncdf4::nc_close(nc), add = TRUE)
vars <- names(nc$var)

expect_true("N2O_flux" %in% vars)
expect_true("CH4_flux" %in% vars)
expect_true(all(c("GPP", "NEE", "TotalResp", "TotSoilCarb") %in% vars))

n2o <- as.numeric(ncdf4::ncvar_get(nc, "N2O_flux"))
ch4 <- as.numeric(ncdf4::ncvar_get(nc, "CH4_flux"))
gpp <- as.numeric(ncdf4::ncvar_get(nc, "GPP"))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of these should be stored as numeric already, and if they aren't then we want to know (as the expect_equal below will do if we skip coercion)

Suggested change
n2o <- as.numeric(ncdf4::ncvar_get(nc, "N2O_flux"))
ch4 <- as.numeric(ncdf4::ncvar_get(nc, "CH4_flux"))
gpp <- as.numeric(ncdf4::ncvar_get(nc, "GPP"))
n2o <- ncdf4::ncvar_get(nc, "N2O_flux")
ch4 <- ncdf4::ncvar_get(nc, "CH4_flux")
gpp <- ncdf4::ncvar_get(nc, "GPP")

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

right! that these should already be numeric , as.numeric() was masking the type check. But ncvar_get() returns a 1-D array (carries dim attribute), so bare comparison with rep() fails on attributes. Switched to as.vector(), which strips the array dimension without coercing type


expect_equal(n2o, rep(0.002 * 1e-3 / ts_s, n), tolerance = 1e-12)
expect_equal(ch4, rep(0.001 * 1e-3 / ts_s, n), tolerance = 1e-12)
expect_equal(gpp, rep(0.30 * 1e-3 / ts_s, n), tolerance = 1e-12)

expect_equal(nc$var$N2O_flux$units, "kg N m-2 s-1")
expect_equal(nc$var$CH4_flux$units, "kg C m-2 s-1")
expect_equal(nc$var$GPP$units, "kg C m-2 s-1")

expect_equal(nc$dim$time$len, n)
expect_match(nc$dim$time$units, "days since 2002")
})


test_that("model2netcdf.SIPNET omits N2O/CH4 when columns absent", {
paths <- setup_sipnet_test(make_base_sipnet(n = 2L))

nc <- ncdf4::nc_open(file.path(paths$outdir, "2002.nc"))
on.exit(ncdf4::nc_close(nc), add = TRUE)
vars <- names(nc$var)

expect_false("N2O_flux" %in% vars)
expect_false("CH4_flux" %in% vars)
expect_true("GPP" %in% vars)
})


test_that("delete.raw removes sipnet.out after conversion", {
paths <- setup_sipnet_test(make_base_sipnet(n = 2L), delete.raw = TRUE)

expect_false(file.exists(paths$out_path))
expect_true(file.exists(file.path(paths$outdir, "2002.nc")))
})
Loading