Skip to content

Commit 5d9fa76

Browse files
committed
calcRootC allows input pools to be split by SW/HW
1 parent 0293664 commit 5d9fa76

4 files changed

Lines changed: 88 additions & 49 deletions

File tree

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Description: Implementation of several components of the Carbon Budget Model of
55
Canadian Forest Service (v3).
66
URL:
77
https://github.com/PredictiveEcology/CBMutils
8-
Version: 2.5.4.9002
8+
Version: 2.5.5.9000
99
Authors@R: c(
1010
person("Céline", "Boisvenue", email = "celine.boisvenue@nrcan-rncan.gc.ca", role = c("aut", "cre")),
1111
person("Alex M", "Chubaty", email = "achubaty@for-cast.ca", role = c("aut"), comment = c(ORCID = "0000-0001-7146-8135")),

R/CBM-tools_calcRootC.R

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ utils::globalVariables(c(
77
#'
88
#' `calcRootC` calculates the mass of carbon in roots pools from above ground pools
99
#'
10-
#' @param aboveGroundC data.table with mass of carbon (tonnes/ha) in the Merch, Foliage and Other pools
11-
#' @param sw_hw a boolean vector indicating if the cohort is softwood (0) or hardwood (1)
10+
#' @param aboveGroundC data.table of above ground biomass with the mass of carbon (tonnes/ha) in each pool.
11+
#' Columns can either be `sw` (Softwood = TRUE, hardwood = FALSE), `Merch`, `Foliage` and `Other`,
12+
#' or `SoftwoodMerch`, `HardwoodMerch`, `SoftwoodFoliage`, `HardwoodFoliage`, `SoftwoodOther`, and `HardwoodOther`.
1213
#' @param a_sw "a" value for softwood root biomass
1314
#' @param b_sw "b" value for softwood root biomass
1415
#' @param a_hw "a" value for hardwood root biomass
@@ -27,47 +28,65 @@ utils::globalVariables(c(
2728
#' @returns data.table with mass of carbon (tonnes/ha) in coarseRoots and fineRoots pools.
2829
#' @export
2930
#'
30-
calcRootC <- function(aboveGroundC, sw_hw,
31+
calcRootC <- function(aboveGroundC,
3132
a_sw = 0.222, b_sw = 1,
3233
a_hw = 1.576, b_hw = 0.615,
3334
a_frp = 0.072, b_frp = 0.354, c_frp = -0.060212,
3435
biomassToCarbonRate = 0.5){
3536

36-
aboveGroundColumns <- c("Merch", "Foliage", "Other")
37+
# Choose column set
38+
AGcols <- list(
39+
c("SoftwoodMerch", "HardwoodMerch", "SoftwoodFoliage", "HardwoodFoliage", "SoftwoodOther", "HardwoodOther"),
40+
c("sw", "Merch", "Foliage", "Other")
41+
)
3742

38-
if(!all(aboveGroundColumns %in% names(aboveGroundC))) {
39-
stop("aboveGroundC needs the columns: ", paste(aboveGroundColumns, collapse = ", "))
40-
}
41-
aboveGroundC <- as.data.table(aboveGroundC)
43+
whichCols <- which(sapply(AGcols, function(cols) all(tolower(cols) %in% tolower(names(aboveGroundC)))))
44+
if (length(whichCols) == 0) stop(
45+
"aboveGroundC needs one of these column sets:\n- ",
46+
paste(sapply(AGcols, function(AGcol) paste(shQuote(AGcol), collapse = ", ")),
47+
collapse = "\n- "))
48+
49+
AGcols <- AGcols[[whichCols[[1]]]]
50+
aboveGroundC <- data.table::as.data.table(aboveGroundC)
51+
data.table::setnames(aboveGroundC, tolower(AGcols), AGcols, skip_absent = TRUE)
52+
aboveGroundC <- aboveGroundC[, .SD, .SDcols = AGcols]
4253

4354
# Calculate the total above ground mass of carbon
44-
totAGC <- rowSums(aboveGroundC[, ..aboveGroundColumns])
55+
if (whichCols == 1){
4556

46-
# Convert Mg/ha of Carbon to Mg/ha of biomass
47-
totAGB <- totAGC / biomassToCarbonRate
57+
aboveGroundC[, SoftwoodAG := rowSums(aboveGroundC[, .(SoftwoodMerch, SoftwoodFoliage, SoftwoodOther)])]
58+
aboveGroundC[, HardwoodAG := rowSums(aboveGroundC[, .(HardwoodMerch, HardwoodFoliage, HardwoodOther)])]
4859

49-
# Calculate root total biomass
50-
if(!all(sw_hw %in% c(1,0))) {
51-
stop("sw_hw needs to be a boolean vector")
60+
}else{
61+
62+
if (!is.logical(aboveGroundC$sw)) stop("aboveGroundC 'sw' column must be logical")
63+
64+
aboveGroundC[, AG := rowSums(aboveGroundC[, .(Merch, Foliage, Other)])]
65+
aboveGroundC[, SoftwoodAG := data.table::fifelse( sw, AG, 0)]
66+
aboveGroundC[, HardwoodAG := data.table::fifelse(!sw, AG, 0)]
67+
aboveGroundC[, AG := NULL]
5268
}
5369

54-
rootTotBiom <- ifelse(sw_hw == 0,
55-
a_sw * totAGB^b_sw,
56-
a_hw * totAGB^b_hw)
70+
# Convert Mg/ha of Carbon to Mg/ha of biomass
71+
aboveGroundC[, SoftwoodAGB := SoftwoodAG / biomassToCarbonRate]
72+
aboveGroundC[, HardwoodAGB := HardwoodAG / biomassToCarbonRate]
73+
74+
# Calculate root total biomass
75+
aboveGroundC[, SoftwoodRootB := a_sw * SoftwoodAGB^b_sw]
76+
aboveGroundC[, HardwoodRootB := a_hw * HardwoodAGB^b_hw]
5777

5878
# Calculate the proportion of fine roots
59-
fineRootProp <- a_frp + b_frp * exp(c_frp * rootTotBiom)
79+
aboveGroundC[, SoftwoodRootProp := a_frp + b_frp * exp(c_frp * SoftwoodRootB)]
80+
aboveGroundC[, HardwoodRootProp := a_frp + b_frp * exp(c_frp * HardwoodRootB)]
6081

82+
# Calculate tonnes/ha of carbon
83+
aboveGroundC[, SoftwoodCoarseRoots := biomassToCarbonRate * SoftwoodRootB * (1 - SoftwoodRootProp)]
84+
aboveGroundC[, SoftwoodFineRoots := biomassToCarbonRate * SoftwoodRootB * SoftwoodRootProp]
85+
aboveGroundC[, HardwoodCoarseRoots := biomassToCarbonRate * HardwoodRootB * (1 - HardwoodRootProp)]
86+
aboveGroundC[, HardwoodFineRoots := biomassToCarbonRate * HardwoodRootB * HardwoodRootProp]
6187

62-
# Calculate the proportion of fine roots
63-
rootBiom <- data.table(
64-
coarseRoots = rootTotBiom * (1 - fineRootProp),
65-
fineRoots = rootTotBiom * fineRootProp
66-
)
88+
return(aboveGroundC[, .(SoftwoodCoarseRoots, HardwoodCoarseRoots, SoftwoodFineRoots, HardwoodFineRoots)])
89+
}
6790

68-
# Reconvert into tonnes/ha of carbon
69-
rootC <- rootBiom * biomassToCarbonRate
7091

71-
return(rootC)
7292

73-
}

man/calcRootC.Rd

Lines changed: 3 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-CBM-tools_calcRootC.R

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,52 @@
22
if (!testthat::is_testing()) source(testthat::test_path("setup.R"))
33

44
test_that("calcRootC", {
5-
ABC <- data.table(Merch = c(0,1),
5+
6+
# Columns type 1
7+
ABC <- data.table(sw = c(TRUE, FALSE),
8+
Merch = c(0,1),
69
Foliage = c(3,1),
7-
Other = c(1,1))
8-
sw_hw = c(0,1)
9-
rootC <- calcRootC(aboveGroundC = ABC, sw_hw = sw_hw)
10-
11-
# Works correctly
12-
expect_identical(
13-
round(rootC,3),
14-
data.table(coarseRoots = c(0.542, 1.570),
15-
fineRoots = c(0.346, 0.802))
10+
Other = c(1,1))
11+
12+
rootC <- calcRootC(aboveGroundC = ABC)
13+
14+
expect_equal(
15+
rootC[, .(CoarseRoots = SoftwoodCoarseRoots + HardwoodCoarseRoots,
16+
FineRoots = SoftwoodFineRoots + HardwoodFineRoots)],
17+
data.table(CoarseRoots = c(0.542, 1.570),
18+
FineRoots = c(0.346, 0.802)),
19+
tolerance = 0.001, scale = 1
1620
)
17-
expect_named(rootC, c("coarseRoots", "fineRoots"))
1821

19-
# Error with missspecified inputs
20-
expect_error(
21-
calcRootC(aboveGroundC = ABC[,.(Merch, Foliage, other = Other)], sw_hw = sw_hw)
22+
# Columns type 2
23+
ABC <- data.table(SoftwoodMerch = c(0,0),
24+
SoftwoodFoliage = c(3,0),
25+
SoftwoodOther = c(1,0),
26+
HardwoodMerch = c(0,1),
27+
HardwoodFoliage = c(0,1),
28+
HardwoodOther = c(0,1))
29+
30+
rootC <- calcRootC(aboveGroundC = ABC)
31+
32+
expect_equal(
33+
rootC,
34+
data.table(SoftwoodCoarseRoots = c(0.542, 0.000),
35+
HardwoodCoarseRoots = c(0.000, 1.570),
36+
SoftwoodFineRoots = c(0.346, 0.000),
37+
HardwoodFineRoots = c(0.000, 0.802)),
38+
tolerance = 0.001, scale = 1
2239
)
2340

41+
# Error with miss specified inputs
2442
expect_error(
25-
calcRootC(aboveGroundC = ABC[,.(Merch, Foliage)], sw_hw = sw_hw)
43+
calcRootC(aboveGroundC = ABC[,.(sw, Merch, Foliage)])
2644
)
2745

2846
expect_error(
29-
calcRootC(aboveGroundC = ABC, sw_hw = c("sw", "hw"))
47+
calcRootC(aboveGroundC = ABC[,.(sw = c(0, 1), Merch, Foliage, Other)])
48+
)
49+
expect_error(
50+
calcRootC(aboveGroundC = ABC[,.(sw = c("sw", "hw"), Merch, Foliage, Other)])
3051
)
31-
3252
})
53+

0 commit comments

Comments
 (0)