Skip to content
Merged
Show file tree
Hide file tree
Changes from 53 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
5599e09
Replace manual unit conversions with ud_convert()
ayushman1210 Dec 14, 2025
2fc0106
Update models/stics/R/met2model.STICS.R
ayushman1210 Dec 15, 2025
c425ca7
Update models/sipnet/R/write_restart.SIPNET.R
ayushman1210 Dec 15, 2025
747277a
Merge branch 'develop' into fix
ayushman1210 Dec 19, 2025
c29e56f
fixes done as per maintainer suggestion
ayushman1210 Dec 19, 2025
a2d79d5
Merge branch 'fix' of https://github.com/ayushman1210/pecan into fix
ayushman1210 Dec 19, 2025
8e2b0a4
Merge branch 'develop' into fix
ayushman1210 Dec 24, 2025
aa8f2d4
Update models/dalec/R/model2netcdf.DALEC.R
ayushman1210 Dec 26, 2025
e6ad156
Update models/dalec/R/model2netcdf.DALEC.R
ayushman1210 Dec 26, 2025
0c2bb74
Update models/gday/R/model2netcdf.GDAY.R
ayushman1210 Dec 26, 2025
1aeddf7
Update tests/testthat/test_model_conversions.R
ayushman1210 Dec 26, 2025
570b899
Update tests/testthat/test_model_conversions.R
ayushman1210 Dec 26, 2025
9970af2
Update tests/testthat/test_model_conversions.R
ayushman1210 Dec 26, 2025
476de3d
Update tests/testthat/test_model_conversions.R
ayushman1210 Dec 26, 2025
2fdc5d9
Merge branch 'develop' into fix
infotroph Jan 7, 2026
46773d1
Merge branch 'develop' into fix
ayushman1210 Jan 12, 2026
20bd418
changes as suggested by the maintainer
ayushman1210 Jan 12, 2026
adecf54
suggested changes
ayushman1210 Jan 12, 2026
6ecf394
Merge branch 'develop' into fix
ayushman1210 Jan 13, 2026
10950c9
Merge branch 'develop' into fix
ayushman1210 Jan 13, 2026
a21b66f
Merge branch 'develop' into fix
ayushman1210 Jan 14, 2026
a7d584a
Merge branch 'develop' into fix
ayushman1210 Jan 16, 2026
f78452c
Merge branch 'develop' into fix
ayushman1210 Jan 16, 2026
c7786e6
Merge branch 'develop' into fix
ayushman1210 Jan 19, 2026
c84dc76
Merge branch 'develop' into fix
ayushman1210 Jan 21, 2026
3b1d45d
Merge branch 'develop' into fix
infotroph Jan 23, 2026
ae48649
Update models/fates/R/write.configs.FATES.R
ayushman1210 Jan 24, 2026
4d9ca18
Update models/fates/R/write.configs.FATES.R
ayushman1210 Jan 24, 2026
b63051f
Update models/sipnet/R/model2netcdf.SIPNET.R
ayushman1210 Jan 24, 2026
014e58f
Update models/fates/R/write.configs.FATES.R
ayushman1210 Jan 24, 2026
d0f49ee
Update models/fates/R/write.configs.FATES.R
ayushman1210 Jan 24, 2026
73db407
Merge branch 'develop' into fix
ayushman1210 Jan 27, 2026
785d156
removed testthat.R updated model2netcdf.SIPNET.R updated model2netcdf…
ayushman1210 Jan 28, 2026
de366f6
Fix: Skip Docker push on forks to avoid ghcr.io authentication errors
ayushman1210 Jan 28, 2026
ec3c96c
Add GDAY unit conversion tests and clean up redundant test files
ayushman1210 Jan 28, 2026
6ac287a
Add unit tests for SIPNET model2netcdf unit conversion changes
ayushman1210 Jan 28, 2026
136db35
Clarify GDAY unit conversion: daily Mg/ha/day not per-year
ayushman1210 Feb 12, 2026
05f6735
Merge branch 'develop' into fix
ayushman1210 Feb 12, 2026
174728b
Update models/sipnet/tests/testthat/test.model2netcdf.SIPNET.R
ayushman1210 Feb 12, 2026
bef3eb8
Address maintainer feedback: revert workflow changes, fix GDAY refere…
ayushman1210 Feb 13, 2026
12539c6
Update SIPNET test to exercise model2netcdf.SIPNET() directly, addres…
ayushman1210 Feb 13, 2026
cfa5d1d
Update GDAY test to exercise model2netcdf.GDAY() directly, addressing…
ayushman1210 Feb 13, 2026
4d2a612
Fix undefined THA_2_KG_M2 in GDAY model2netcdf by using ud_convert
ayushman1210 Feb 13, 2026
b8d8130
Fix GDAY unit conversion test to use manual calculation instead of pr…
ayushman1210 Feb 13, 2026
4427363
fixed the ci-failure
ayushman1210 Feb 15, 2026
4ba11dc
Merge branch 'develop' into fix
ayushman1210 Feb 22, 2026
b982d92
Merge branch 'develop' into fix
ayushman1210 Feb 26, 2026
df85039
Update models/gday/tests/testthat/test.model2netcdf.GDAY.R
ayushman1210 Feb 28, 2026
d7b2434
Update models/gday/R/model2netcdf.GDAY.R
ayushman1210 Feb 28, 2026
110ffef
Update models/gday/R/model2netcdf.GDAY.R
ayushman1210 Feb 28, 2026
dbeaf47
Merge branch 'develop' into fix
ayushman1210 Mar 3, 2026
3502db0
Standardize unit conversions and fix tests for PR #3719
ayushman1210 Mar 3, 2026
d7e5ef3
Add TODO comment for woodCreation in SIPNET
ayushman1210 Mar 3, 2026
eab202c
Update models/sipnet/R/model2netcdf.SIPNET.R
infotroph Mar 6, 2026
68421f3
update deps
infotroph Mar 6, 2026
da2fab8
Merge branch 'develop' into fix
ayushman1210 Mar 6, 2026
bdd4a76
hack around test failure until full V2 support replaces this
infotroph Mar 6, 2026
b280b19
more conditionals
infotroph Mar 7, 2026
b972c26
Merge branch 'develop' into fix
infotroph Mar 7, 2026
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
17 changes: 17 additions & 0 deletions base/utils/tests/testthat/test-ud_convert.R
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,21 @@ test_that("ud_convert() warns with wrong input units for difftime", {
expect_warning(ud_convert(as.difftime("12:00:00"), u1 = "years", u2 = "minutes"))
#should still error if units are not convertible
expect_error(ud_convert(as.difftime("12:00:00"), u1 = "kilograms", u2 = "minutes"))
})

test_that("model-specific pool conversions", {
# DALEC/SIPNET C pools
expect_equal(ud_convert(100, "g/m2", "kg/m2"), 0.1)
# GDAY pools
expect_equal(ud_convert(10, "Mg/ha", "kg/m2"), 1)
})

test_that("model-specific flux conversions", {
# DALEC/SIPNET C fluxes
expect_equal(ud_convert(86400, "g/m2/d", "kg/m2/s"), 0.001, tolerance = 1e-10)
})

test_that("photosynthesis parameters", {
# Photosynthesis energy parameters
expect_equal(ud_convert(1000, "J/mol", "kJ/mol"), 1)
})
30 changes: 15 additions & 15 deletions models/dalec/R/model2netcdf.DALEC.R
Original file line number Diff line number Diff line change
Expand Up @@ -83,22 +83,22 @@ model2netcdf.DALEC <- function(outdir, sitelat, sitelon, start_date, end_date) {

## Setup outputs for netCDF file in appropriate units
output <- list()
## Fluxes
output[[1]] <- (sub.DALEC.output[, 1] * 0.001)/timestep.s # Autotrophic Respiration in kgC/m2/s
output[[2]] <- (sub.DALEC.output[, 21] + sub.DALEC.output[, 23]) * 0.001 / timestep.s # Heterotrophic Resp kgC/m2/s
output[[3]] <- (sub.DALEC.output[, 31] * 0.001)/timestep.s # GPP in kgC/m2/s
output[[4]] <- (sub.DALEC.output[, 33] * 0.001)/timestep.s # NEE in kgC/m2/s
output[[5]] <- (sub.DALEC.output[, 3] + sub.DALEC.output[, 5] + sub.DALEC.output[, 7]) * 0.001/timestep.s # NPP kgC/m2/s
output[[6]] <- (sub.DALEC.output[, 9] * 0.001) / timestep.s # Leaf Litter Flux, kgC/m2/s
output[[7]] <- (sub.DALEC.output[, 11] * 0.001) / timestep.s # Woody Litter Flux, kgC/m2/s
output[[8]] <- (sub.DALEC.output[, 13] * 0.001) / timestep.s # Root Litter Flux, kgC/m2/s
## Fluxes (convert g/m2/day to kg/m2/s)
output[[1]] <- PEcAn.utils::ud_convert(sub.DALEC.output[, 1], "g/m2/d", "kg/m2/s") # Autotrophic Respiration
output[[2]] <- PEcAn.utils::ud_convert(sub.DALEC.output[, 21] + sub.DALEC.output[, 23], "g/m2/d", "kg/m2/s") # Heterotrophic Resp
output[[3]] <- PEcAn.utils::ud_convert(sub.DALEC.output[, 31], "g/m2/d", "kg/m2/s") # GPP
output[[4]] <- PEcAn.utils::ud_convert(sub.DALEC.output[, 33], "g/m2/d", "kg/m2/s") # NEE
output[[5]] <- PEcAn.utils::ud_convert(sub.DALEC.output[, 3] + sub.DALEC.output[, 5] + sub.DALEC.output[, 7], "g/m2/d", "kg/m2/s") # NPP
output[[6]] <- PEcAn.utils::ud_convert(sub.DALEC.output[, 9], "g/m2/d", "kg/m2/s") # Leaf Litter Flux
output[[7]] <- PEcAn.utils::ud_convert(sub.DALEC.output[, 11], "g/m2/d", "kg/m2/s") # Woody Litter Flux
output[[8]] <- PEcAn.utils::ud_convert(sub.DALEC.output[, 13], "g/m2/d", "kg/m2/s") # Root Litter Flux

## Pools
output[[9]] <- (sub.DALEC.output[, 15] * 0.001) # Leaf Carbon, kgC/m2
output[[10]] <- (sub.DALEC.output[, 17] * 0.001) # Wood Carbon, kgC/m2
output[[11]] <- (sub.DALEC.output[, 19] * 0.001) # Root Carbon, kgC/m2
output[[12]] <- (sub.DALEC.output[, 27] * 0.001) # Litter Carbon, kgC/m2
output[[13]] <- (sub.DALEC.output[, 29] * 0.001) # Soil Carbon, kgC/m2
## Pools (convert g/m2 to kg/m2)
output[[9]] <- PEcAn.utils::ud_convert(sub.DALEC.output[, 15], "g/m2", "kg/m2") # Leaf Carbon
output[[10]] <- PEcAn.utils::ud_convert(sub.DALEC.output[, 17], "g/m2", "kg/m2") # Wood Carbon
output[[11]] <- PEcAn.utils::ud_convert(sub.DALEC.output[, 19], "g/m2", "kg/m2") # Root Carbon
output[[12]] <- PEcAn.utils::ud_convert(sub.DALEC.output[, 27], "g/m2", "kg/m2") # Litter Carbon
output[[13]] <- PEcAn.utils::ud_convert(sub.DALEC.output[, 29], "g/m2", "kg/m2") # Soil Carbon

## standard composites
output[[14]] <- output[[1]] + output[[2]] # Total Respiration
Expand Down
8 changes: 4 additions & 4 deletions models/fates/R/write.configs.FATES.R
Original file line number Diff line number Diff line change
Expand Up @@ -307,25 +307,25 @@ write.config.FATES <- function(defaults, trait.values, settings, run.id){
# Ha activation energy for vcmax - FATES units: J/mol
if(var == "Ha_Modified_Arrhenius_Vcmax"){
ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_vcmaxha', start = ipft, count = 1,
vals=pft[v]*1000) ## convert from kj/mol to J/mol (FATES units)
vals=PEcAn.utils::ud_convert(pft[v], "kJ/mol", "J/mol"))
}

# Hd deactivation energy for vcmax - FATES units: J/mol
if(var == "Hd_Modified_Arrhenius_Vcmax"){
ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_vcmaxhd', start = ipft, count = 1,
vals=pft[v]*1000) ## convert from kj/mol to J/mol (FATES units)
vals = PEcAn.utils::ud_convert(pft[v], "kJ/mol", "J/mol"))
}

# Ha activation energy for Jmax - FATES units: J/mol
if(var == "Ha_Modified_Arrhenius_Jmax"){
ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_jmaxha', start = ipft, count = 1,
vals=pft[v]*1000) ## convert from kj/mol to J/mol (FATES units)
vals = PEcAn.utils::ud_convert(pft[v], "kJ/mol", "J/mol"))
}

# Hd deactivation energy for Jmax - FATES units: J/mol
if(var == "Hd_Modified_Arrhenius_Jmax"){
ncdf4::ncvar_put(nc=fates.param.nc, varid='fates_jmaxhd', start = ipft, count = 1,
vals=pft[v]*1000) ## convert from kj/mol to J/mol (FATES units)
vals = PEcAn.utils::ud_convert(pft[v], "kJ/mol", "J/mol"))
}

# deltaS Vcmax - BETY units:J/mol/K; FATES units: J/mol/K
Expand Down
3 changes: 2 additions & 1 deletion models/gday/DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ Imports:
lubridate (>= 1.6.0),
ncdf4 (>= 1.15)
Suggests:
testthat (>= 1.0.2)
testthat (>= 1.0.2),
withr
SystemRequirements: GDAY
OS_type: unix
License: BSD_3_clause + file LICENSE
Expand Down
26 changes: 13 additions & 13 deletions models/gday/R/model2netcdf.GDAY.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@
model2netcdf.GDAY <- function(outdir, sitelat, sitelon, start_date, end_date) {


G_2_KG <- 0.001
TONNES_PER_HA_TO_G_M2 <- 100
THA_2_KG_M2 <- TONNES_PER_HA_TO_G_M2 * 0.001

### Read in model output in GDAY format
GDAY.output <- utils::read.csv(file.path(outdir, "gday_out.csv"), header = TRUE, sep = ",", skip = 1)
Expand All @@ -44,17 +41,20 @@ model2netcdf.GDAY <- function(outdir, sitelat, sitelon, start_date, end_date) {
output <- list()

## standard variables: C-Fluxes
output[[1]] <- (sub.GDAY.output[, "auto_resp"] * THA_2_KG_M2) / timestep.s
output[[2]] <- (sub.GDAY.output[, "hetero_resp"] * THA_2_KG_M2) / timestep.s
output[[3]] <- (sub.GDAY.output[, "auto_resp"] + sub.GDAY.output[, "hetero_resp"] *
THA_2_KG_M2) / timestep.s
output[[4]] <- (sub.GDAY.output[, "gpp"] * THA_2_KG_M2) / timestep.s
output[[5]] <- (sub.GDAY.output[, "nep"] * -1 * THA_2_KG_M2) / timestep.s
output[[6]] <- (sub.GDAY.output[, "npp"] * THA_2_KG_M2) / timestep.s
## NOTE: GDAY outputs daily accumulated values in Mg/ha/day
## Transform all to kg/m2/sec for PEcAn output
output[[1]] <- PEcAn.utils::ud_convert(sub.GDAY.output[, "auto_resp"], "Mg/ha/day", "kg/m2/s")
output[[2]] <- PEcAn.utils::ud_convert(sub.GDAY.output[, "hetero_resp"], "Mg/ha/day", "kg/m2/s")
output[[3]] <- PEcAn.utils::ud_convert(sub.GDAY.output[, "auto_resp"] + sub.GDAY.output[, "hetero_resp"], "Mg/ha/day", "kg/m2/s")
output[[4]] <- PEcAn.utils::ud_convert(sub.GDAY.output[, "gpp"], "Mg/ha/day", "kg/m2/s")
output[[5]] <- PEcAn.utils::ud_convert(sub.GDAY.output[, "nep"] * -1, "Mg/ha/day", "kg/m2/s")
output[[6]] <- PEcAn.utils::ud_convert(sub.GDAY.output[, "npp"], "Mg/ha/day", "kg/m2/s")

## standard variables: C-State
output[[7]] <- (sub.GDAY.output[, "stem"] + sub.GDAY.output[, "branch"] * THA_2_KG_M2) / timestep.s
output[[8]] <- (sub.GDAY.output[, "soilc"] * THA_2_KG_M2) / timestep.s
## standard variables: C-State (pools)
# NOTE: GDAY outputs stocks in Mg/ha.
# Transform to kg/m2 for PEcAn output
output[[7]] <- PEcAn.utils::ud_convert(sub.GDAY.output[, "stem"] + sub.GDAY.output[, "branch"], "Mg/ha", "kg/m2")
output[[8]] <- PEcAn.utils::ud_convert(sub.GDAY.output[, "soilc"], "Mg/ha", "kg/m2")
output[[9]] <- (sub.GDAY.output[, "lai"])

## standard variables: water fluxes
Expand Down
7 changes: 7 additions & 0 deletions models/gday/tests/testthat/data/gday_out.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# GDAY output
year,day,auto_resp,hetero_resp,gpp,nep,npp,stem,branch,soilc,lai,et,transpiration
2004,1,0.01,0.02,0.05,-0.03,0.03,100,50,200,2,0.5,0.3
2004,2,0.01,0.02,0.05,-0.03,0.03,100,50,200,2,0.5,0.3
2004,3,0.01,0.02,0.05,-0.03,0.03,100,50,200,2,0.5,0.3
2004,4,0.01,0.02,0.05,-0.03,0.03,100,50,200,2,0.5,0.3
2004,5,0.01,0.02,0.05,-0.03,0.03,100,50,200,2,0.5,0.3
54 changes: 54 additions & 0 deletions models/gday/tests/testthat/test.model2netcdf.GDAY.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
##' Test for GDAY model2netcdf unit conversions
Comment thread
ayushman1210 marked this conversation as resolved.
##'
##' This test verifies that the unit conversions in model2netcdf.GDAY are correct.
##'
##' Reference: https://github.com/PecanProject/pecan/pull/3719
##' GDAY outputs daily values in Mg/ha/day, which should be converted to kg/m2/s
##'
##' Conversion factors:
##' 1 Mg/ha = 0.1 kg/m2 (area conversion)
##' 1 day = 86400 seconds
##' Therefore: 1 Mg/ha/day = 0.1 / 86400 kg/m2/s = 1.157e-6 kg/m2/s

context("GDAY model2netcdf unit conversions")

test_that("model2netcdf.GDAY runs without error and produces netCDF", {
outdir <- withr::local_tempdir()
file.copy("data/gday_out.csv", outdir)

# Run the function
expect_silent(
model2netcdf.GDAY(
outdir = outdir,
sitelat = 40,
sitelon = -88,
start_date = "2004-01-01",
end_date = "2004-12-31"
)
)

# Check that netCDF file is created
nc_file <- file.path(outdir, "2004.nc")
expect_true(file.exists(nc_file))

# Check that we can read the output
output <- PEcAn.utils::read.output(
ncfiles = nc_file,
variables = c("GPP", "AbvGrndWood"),
dataframe = TRUE,
verbose = FALSE,
print_summary = FALSE
)
# GPP should be in kg/m2/s (converted from Mg/ha/day)
secs_day <- 86400
kg_Mg <- 1000
m2_ha <- 10000
gday2pecan <- kg_Mg/m2_ha/secs_day
expect_equal(nrow(output), 5)
expect_equal(output$GPP, rep(0.5, 5) * gday2pecan, tolerance = 1e-6)

# AbvGrndWood is a stock (Mg/ha), not a flux (Mg/ha/day).
# Conversion: 1 Mg/ha = 0.1 kg/m2
stock_conv <- 0.1
expect_equal(output$AbvGrndWood, rep(150, 5) * stock_conv, tolerance = 1e-6)
})
Comment thread
ayushman1210 marked this conversation as resolved.
47 changes: 24 additions & 23 deletions models/sipnet/R/model2netcdf.SIPNET.R
Original file line number Diff line number Diff line change
Expand Up @@ -134,21 +134,19 @@ model2netcdf.SIPNET <- function(outdir, sitelat, sitelon, start_date, end_date,
bounds <- round(bounds,4)

## Setup outputs for netCDF file in appropriate units
output <- list(
"GPP" = (sub.sipnet.output$gpp * 0.001) / timestep.s, # GPP in kgC/m2/s
"NPP" = (sub.sipnet.output$gpp * 0.001) / timestep.s - ((sub.sipnet.output$rAboveground *
0.001) / timestep.s + (sub.sipnet.output$rRoot * 0.001) / timestep.s), # NPP in kgC/m2/s. Post SIPNET calculation
"TotalResp" = (sub.sipnet.output$rtot * 0.001) / timestep.s, # Total Respiration in kgC/m2/s
"AutoResp" = (sub.sipnet.output$rAboveground * 0.001) / timestep.s + (sub.sipnet.output$rRoot *
0.001) / timestep.s, # Autotrophic Respiration in kgC/m2/s
"HeteroResp" = ((sub.sipnet.output$rSoil - sub.sipnet.output$rRoot) * 0.001) / timestep.s, # Heterotrophic Respiration in kgC/m2/s
"SoilResp" = (sub.sipnet.output$rSoil * 0.001) / timestep.s, # Soil Respiration in kgC/m2/s
"NEE" = (sub.sipnet.output$nee * 0.001) / timestep.s, # NEE in kgC/m2/s
"AbvGrndWood" = (sub.sipnet.output$plantWoodC * 0.001), # Above ground wood kgC/m2
"leaf_carbon_content" = (sub.sipnet.output$plantLeafC * 0.001), # Leaf C kgC/m2
"TotLivBiom" = (sub.sipnet.output$plantWoodC * 0.001) + (sub.sipnet.output$plantLeafC * 0.001) +
(sub.sipnet.output$coarseRootC + sub.sipnet.output$fineRootC) * 0.001, # Total living C kgC/m2
"TotSoilCarb" = (sub.sipnet.output$soil * 0.001) + (sub.sipnet.output$litter * 0.001) # Total soil C kgC/m2
output <- list(
"GPP" = PEcAn.utils::ud_convert(sub.sipnet.output$gpp, "g/m2", "kg/m2") / timestep.s,
"NPP" = PEcAn.utils::ud_convert(sub.sipnet.output$gpp - (sub.sipnet.output$rAboveground + sub.sipnet.output$rRoot), "g/m2", "kg/m2") / timestep.s,
"TotalResp" = PEcAn.utils::ud_convert(sub.sipnet.output$rtot, "g/m2", "kg/m2") / timestep.s,
"AutoResp" = (PEcAn.utils::ud_convert(sub.sipnet.output$rAboveground + sub.sipnet.output$rRoot, "g/m2", "kg/m2")) / timestep.s,
"HeteroResp" = PEcAn.utils::ud_convert(sub.sipnet.output$rSoil - sub.sipnet.output$rRoot, "g/m2", "kg/m2") / timestep.s,
"SoilResp" = PEcAn.utils::ud_convert(sub.sipnet.output$rSoil, "g/m2", "kg/m2") / timestep.s,
"NEE" = PEcAn.utils::ud_convert(sub.sipnet.output$nee, "g/m2", "kg/m2") / timestep.s,
"AbvGrndWood" = PEcAn.utils::ud_convert(sub.sipnet.output$plantWoodC, "g/m2", "kg/m2"),
"leaf_carbon_content" = PEcAn.utils::ud_convert(sub.sipnet.output$plantLeafC, "g/m2", "kg/m2"),
"TotLivBiom" = (PEcAn.utils::ud_convert(sub.sipnet.output$plantWoodC + sub.sipnet.output$plantLeafC +
sub.sipnet.output$coarseRootC + sub.sipnet.output$fineRootC, "g/m2", "kg/m2")),
"TotSoilCarb" = PEcAn.utils::ud_convert(sub.sipnet.output$soil + sub.sipnet.output$litter, "g/m2", "kg/m2")
)
if (revision == "unk") {
## *** NOTE : npp in the sipnet output file is actually evapotranspiration, this is due to a bug in sipnet.c : ***
Expand All @@ -164,8 +162,8 @@ model2netcdf.SIPNET <- function(outdir, sitelat, sitelon, start_date, end_date,
output[["SoilMoist"]] <- (sub.sipnet.output$soilWater * 10) # Soil moisture kgW/m2
output[["SoilMoistFrac"]] <- (sub.sipnet.output$soilWetnessFrac) # Fractional soil wetness
output[["SWE"]] <- (sub.sipnet.output$snow * 10) # SWE
output[["litter_carbon_content"]] <- sub.sipnet.output$litter * 0.001 ## litter kgC/m2
output[["litter_mass_content_of_water"]] <- (sub.sipnet.output$litterWater * 10) # Litter water kgW/m2
output[["litter_carbon_content"]] <- PEcAn.utils::ud_convert(sub.sipnet.output$litter, "g/m2", "kg/m2")
output[["litter_mass_content_of_water"]] <- PEcAn.utils::ud_convert(sub.sipnet.output$litterWater, "cm", "mm") # labeled elsewhere as kg water m-2 (which is equivalent but ud_convert doesn't know that)
#calculate LAI for standard output
# LAI = plantLeafC / leafCSpWt
# both operands are in carbon units (gC/m2 and gC/m2_leaf),
Expand All @@ -176,17 +174,20 @@ model2netcdf.SIPNET <- function(outdir, sitelat, sitelon, start_date, end_date,
leafCSpWt <- param[param[, 1] == "leafCSpWt", 2]
SLA <- 1000 / leafCSpWt # m2 leaf / kg C
output[["LAI"]] <- output[["leaf_carbon_content"]] * SLA
output[["fine_root_carbon_content"]] <- sub.sipnet.output$fineRootC * 0.001 ## fine_root_carbon_content kgC/m2
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
output[["fine_root_carbon_content"]] <- PEcAn.utils::ud_convert(sub.sipnet.output$fineRootC, "g/m2", "kg/m2")
output[["coarse_root_carbon_content"]] <- PEcAn.utils::ud_convert(sub.sipnet.output$coarseRootC, "g/m2", "kg/m2")
# TODO 2026-02-27 CKB: A longstanding comment here claims woodCreation
# "is daily in SIPNET", but the Sipnet docs claim it's per timestep like
# the other tracker variables. Investigate and resolve.
Comment thread
infotroph marked this conversation as resolved.
Outdated
output[["GWBI"]] <- PEcAn.utils::ud_convert(sub.sipnet.output$woodCreation, "g/m2/day", "kg/m2/s")
output[["AGB"]] <- PEcAn.utils::ud_convert(sub.sipnet.output$plantWoodC + sub.sipnet.output$plantLeafC, "g/m2", "kg/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
output[["N2O_flux"]] <- PEcAn.utils::ud_convert(sub.sipnet.output$n2o, "g/m2", "kg/m2") / 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
output[["CH4_flux"]] <- PEcAn.utils::ud_convert(sub.sipnet.output$ch4, "g/m2", "kg/m2") / timestep.s
# convert g C m-2 per timestep -> kg C m-2 s-1
}
output[["time_bounds"]] <- c(rbind(bounds[,1], bounds[,2]))
Expand Down
3 changes: 1 addition & 2 deletions models/sipnet/R/write_restart.SIPNET.R
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,11 @@ write_restart.SIPNET <- function(outdir, runid, start.time, stop.time, settings,

## Converting to sipnet units
prior.sla <- new.params[[which(!names(new.params) %in% c("soil", "soil_SDA", "restart"))[1]]]$SLA
unit.conv <- 2 * (10000 / 1) * (1 / 1000) * (3.154 * 10^7) # kgC/m2/s -> Mg/ha/yr

analysis.save <- list()

if ("NPP" %in% variables) {
analysis.save[[length(analysis.save) + 1]] <- PEcAn.utils::ud_convert(new.state$NPP, "kg/m^2/s", "Mg/ha/yr") #*unit.conv -> Mg/ha/yr
analysis.save[[length(analysis.save) + 1]] <- PEcAn.utils::ud_convert(new.state$NPP, "kg/m^2/s", "Mg/ha/yr")
names(analysis.save[[length(analysis.save)]]) <- c("NPP")
}

Expand Down
2 changes: 1 addition & 1 deletion models/stics/R/met2model.STICS.R
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ met2model.STICS <- function(in.path, in.prefix, outfolder, start_date, end_date,
# column 10: rainfall (mm.j-1)
Rain <- ncdf4::ncvar_get(nc, "precipitation_flux") # kg m-2 s-1
Rain <- Rain[ydays %in% simdays]
raini <- tapply(Rain * 86400, ind, mean, na.rm = TRUE)
raini <- tapply(PEcAn.utils::ud_convert(Rain, "kg/m2/s", "kg/m2/d"), ind, mean, na.rm = TRUE) # 1 kg/m2 = 1 mm water
weather_df[ ,10] <- round(raini, digits = 2) # precipitation (mm d-1)

# column 11: wind (m.s-1)
Expand Down
Loading