Skip to content

Commit f0b81e5

Browse files
authored
Merge pull request #88 from PredictiveEcology/suz-calcRootC
calcRootC allows input pools to be split by SW/HW
2 parents 0293664 + 6786ada commit f0b81e5

4 files changed

Lines changed: 90 additions & 50 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: 48 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11

22
utils::globalVariables(c(
3-
"..aboveGroundColumns"
3+
"sw", "AG", "SoftwoodAG", "HardwoodAG", "SoftwoodAGB", "HardwoodAGB",
4+
"SoftwoodRootB", "HardwoodRootB", "SoftwoodRootProp", "HardwoodRootProp"
45
))
56

67
#' `calcRootC`
78
#'
89
#' `calcRootC` calculates the mass of carbon in roots pools from above ground pools
910
#'
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)
11+
#' @param aboveGroundC data.table of above ground biomass with the mass of carbon (tonnes/ha) in each pool.
12+
#' Columns can either be `sw` (Softwood = TRUE, hardwood = FALSE), `Merch`, `Foliage` and `Other`,
13+
#' or `SoftwoodMerch`, `HardwoodMerch`, `SoftwoodFoliage`, `HardwoodFoliage`, `SoftwoodOther`, and `HardwoodOther`.
1214
#' @param a_sw "a" value for softwood root biomass
1315
#' @param b_sw "b" value for softwood root biomass
1416
#' @param a_hw "a" value for hardwood root biomass
@@ -27,47 +29,65 @@ utils::globalVariables(c(
2729
#' @returns data.table with mass of carbon (tonnes/ha) in coarseRoots and fineRoots pools.
2830
#' @export
2931
#'
30-
calcRootC <- function(aboveGroundC, sw_hw,
32+
calcRootC <- function(aboveGroundC,
3133
a_sw = 0.222, b_sw = 1,
3234
a_hw = 1.576, b_hw = 0.615,
3335
a_frp = 0.072, b_frp = 0.354, c_frp = -0.060212,
3436
biomassToCarbonRate = 0.5){
3537

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

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

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

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

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

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

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

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

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

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

71-
return(rootC)
7293

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)