-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Shrubs biomass calculation in temperate forests #41
Comments
The steps described above concern the entire process for calculating biomass. For now, however, I would like to focus on the specific process to translate DBH (from users data) to DBA (required in some equations). With that translation we can then calculate the biomass of each individual stem (each row in a dataset with a DBH value), and then users can summarize the data however they want, e.g. totals by tag, species, quadrat. This issue is mentioned in your step a.4 as "calculate the diameter at the base of shrub, assuming area preserving", but How do we do this? (I'll now search for an answer in the code by Valentine that you sent me.) Notice that once we translate DBH to DBA, the two pathways merge. That is, we no longer have a pathway (a) and a pathway (b), but a table with equations dependent on DBH or DBA that we can evaluate using DBH values from the user. Some more general thoughts that I’ll clarify as I reveal the differences between the processes to calculate biomass of shrubs versus anything. Quotes are answers by Erika Gonzalez.
|
@gonzalezeb , I may be very wrong, so please correct me. If BD is equivalent to DBA, then Valentine's code shows that DBH and DBA are equivalent when the number of stems in a shrub is one. That means that to calculate the biomass of each individual stem in a shrub we can use directly DBH. However, I'm confused when it comes to calculating the total biomass in a stem. It seems intuitive that the combined biomass of all stems of a shrub should be the sum of the biomass of the individual stems. Yet the equations I get show that the result is instead the square root of the sum of each DBH to the power of two ( From Valentine's code ## calculate basal area contribution of each stem within a tree
BA <- (pi / 4) * x.shrub.BD$dbh^2 # basal area (at 1.3 m) in mm
tree.sum.BA.un <- tapply(BA, x.shrub.BD$tag, sum, na.rm = T) # sum of basal areas per tree
# ... more code here
## calulate diameter at base of shrub, assuming area preserving
tree.BD <- data.frame(tag = names(tree.sum.BA.un), BD = sqrt(tree.sum.BA.un / pi) * 2)
Case when a shrub has one stemWhen a shrub has one stem, the sum of basal area equal basal area: tree.sum.BA.un = BA = (pi / 4) * dbh^2 Inserting BA into the formula of BD we can simplify terms until we end up with DBH. If follows: BD = sqrt(tree.sum.BA.un / pi) * 2 =
sqrt(BA / pi) * 2 =
sqrt((pi / 4) * dbh^2 / pi) * 2 =
sqrt( pi / 4 * dbh^2 / pi) * 2 =
sqrt( 1 / 4 * dbh^2 ) * 2 =
sqrt( 1 / 2^(1/2) * dbh^2 ) * 2 =
sqrt(1) / sqrt(2^(1/2)) * sqrt(dbh^2) * 2 =
1 / 2 * dbh * 2 =
dbh/2 * 2 =
dbh = BD Case when a shrub has multiple stemsBD = sqrt(tree.sum.BA.un / pi) * 2 =
sqrt(BA1 + BA2 / pi) * 2 =
sqrt( pi / 4 * (dbh1^2 + dbh2^2) / pi) * 2 =
sqrt(4) * sqrt(dbh1^2 + dbh2^2) * 2 =
2 * sqrt(dbh1^2 + dbh2^2) * 2 =
sqrt(dbh1^2 + dbh2^2) =
sqrt(dbh1^2 + dbh2^2) = |
@gonzalezeb, whenever you can, I'd love to have your thoughts (and maybe Valentine's) about my idea that DBH and DBA may be equivalent (comment just above this one). |
Mauro, we think your approach is correct. DBH is equivalent to DBA when the shrub has only one stem. But when it has multiple stem, we just need to make sure to redistribute the biomass of main stem to other stems. |
I think I will include @ValentineHerr if we have more questions.. |
Hi @maurolepore , A - If the DBH is needed (equations probably developed for shrubs that have a "tree" shape, with some branches along the stem), we need to apply the equation on the main stem of the shrub because we think that studies outside of ForestGEO do not measure every single stem at 1.3m but instead find the main obvious stem and measure that one only. From that one stem they get the whole AGB. If we were applying the equation on every single stem of the shrub we would overestimate the AGB because it would be assuming that each stem is actually its own shrub. B. If the Basal Diameter is needed (equations probably developed for shrubs that have all their stems coming out of the stump), we need to estimate that basal diameter. Krista's idea was to assume "area preserving" which means that the sum of the area of all stems at 1.3m is equal to the area at the stump. From that basal area that we just calculated, we get the basal diameter (You found our that we can use the sqrt( dbh1^2 + dbh2^2 + ... ) instead of doing the whole area preserving calculation. Good). Is that clarification of any help ? |
@gonzalezeb and @ValentineHerr, In preparation for my upcoming visit I'm reviewing this issue and I would like to capture this discussion by writing some code (building on top of @ValentineHerr's code and ideas). But before I do that, I would like to touch base and ask you if there is anything new I should be aware of. My goal is to develop an easy way to calculate biomass given equations expressed in terms of |
Adding to #41 (comment), this flowchart highlights diffences between stem and tree tables for tree and shrub life forms. I'll develop my thougths and code a bit more then may ask a few questions. For tree tables there is information only for main stems, so each row gives the biomass of each main stem. For stem tables:
|
Case when data is suspected to be a tree-table: * tree biomass is that of main stem, not entire tree * shrub biomass is that of entire shrub, not the row-specific stem Case when data is suspected to be a tree table: * shrub biomass may be overestimated because we still don't handle this correctly. (ropensci/allodb#41) Also, new scbi_small_multi_stem data for tests and examples
The division is less clear than I had expected. Below you can see equations which independent variable is library(tidyverse)
allodb::master_tidy() %>%
select(life_form, equation_form, independent_variable) %>%
unique()
#> Joining `equations` and `sitespecies` by 'equation_id'; then `sites_info` by 'site'.
#> # A tibble: 31 x 3
#> life_form equation_form independent_variable
#> <chr> <chr> <chr>
#> 1 Tree 10^(a+b*(log10(dbh^c))) DBH
#> 2 Tree exp(a+b*log(dbh)) DBH
#> 3 Tree 10^(a+b*(log10(dbh))) DBH
#> 4 Shrub exp(a+b*log(dbh)) DBH
#> 5 Shrub, small tree exp(a+b*log(dbh)) DBH
#> 6 Tree or Shrub exp(a+b*log(dbh)) DBH
#> 7 Tree a+(b*dbh)+c*(dbh^d) DBH
#> 8 Shrub a*(dba^b) DBA
#> 9 Tree a*(dbh^b) DBH
#> 10 Shrub a*(dbh^b) DBH
#> # ... with 21 more rows What criteria should I use to pick the equations that follow the path that @ValentineHerr described above for shrubs? Would this be okay? (i.e. anything containing "shrub" is a shrub). is_shrub <- function(x) {
grepl("shrub", x, ignore.case = TRUE)
}
is_shrub(c("Tree", "Shrub", "Shrub, small tree", "Tree or Shrub"))
#> [1] FALSE TRUE TRUE TRUE |
I think your suggestion is good ("anything containing "shrub" is a shrub). |
…ubs (ropensci/allodb#41) Also: 1. New warnings when data is suspected to be a tree-table: * warn that tree biomass is that of main stem, not entire tree * warn that shrub biomass is that of entire shrub, not the row-specific stem 2. Add new data scbi_stem_shrub_tiny and scbi_stem_tree_tiny
We now correclty handly shrub biomass for equaitons which independent variable is library(tidyverse)
library(fgeo.biomass)
shrubs <- fgeo.biomass::scbi_stem_shrub_tiny
equations <- shrubs %>%
add_species(scbi_species, "scbi") %>%
allo_find(dbh_unit = "mm")
#> Adding `site`.
#> Overwriting `sp`; it now stores Latin species names.
#> Adding `rowid`.
#> * Matching equations by site and species.
#> * Refining equations according to dbh.
#> * Using generic equations where expert equations can't be found.
#> Warning: Can't find equations for 26 rows (inserting `NA`).
biomass <- equations %>%
allo_evaluate(dbh_unit = "mm")
#> Shrub `biomass` given for main stems only but applies to the whole shrub.
#> Guessing `dbh` in [mm]
#> You may provide the `dbh` unit manually via the argument `dbh_unit`.
#> Converting `dbh` based on `dbh_unit`.
#> `biomass` values are given in [kg].
# Biomass given only for main stem but representes whole shrub biomass
with_biomass <- left_join(equations, biomass) %>%
select(1:6, dbh, biomass)
#> Joining, by = "rowid"
with_biomass
#> # A tibble: 34 x 8
#> rowid treeID stemID tag StemTag sp dbh biomass
#> <int> <dbl> <dbl> <dbl> <dbl> <chr> <dbl> <dbl>
#> 1 1 1111 1111 10133 1 lindera benzoin 50.9 5.56
#> 2 2 1111 32221 10133 2 lindera benzoin 18.5 NA
#> 3 3 1111 36962 10133 3 lindera benzoin 17.2 NA
#> 4 4 1111 38540 10133 4 lindera benzoin 17.2 NA
#> 5 5 1111 39225 10133 5 lindera benzoin 17.1 NA
#> 6 6 1111 39581 10133 6 lindera benzoin 15.9 NA
#> 7 7 2333 2333 20035 1 lindera benzoin 56.9 7.27
#> 8 8 2333 32434 20035 10 lindera benzoin 12.1 NA
#> 9 9 2333 37071 20035 11 lindera benzoin 15.9 NA
#> 10 10 2333 38598 20035 12 lindera benzoin 11.5 NA
#> # ... with 24 more rows
# More clearly showing whole-shrub biomass
left_join(equations, biomass) %>%
select(1:6, dbh, biomass) %>%
group_by(treeID, sp) %>%
summarise(whole_shrub_biomass = sum(biomass, na.rm = TRUE))
#> Joining, by = "rowid"
#> # A tibble: 5 x 3
#> # Groups: treeID [5]
#> treeID sp whole_shrub_biomass
#> <dbl> <chr> <dbl>
#> 1 1111 lindera benzoin 5.56
#> 2 2333 lindera benzoin 7.27
#> 3 5476 lindera benzoin 9.05
#> 4 22479 lindera benzoin 3.34
#> 5 28182 lindera benzoin 5.85 Created on 2019-04-03 by the reprex package (v0.2.1) |
This example includes both shrubs and trees: library(tidyverse)
library(fgeo.biomass)
shrubs <- fgeo.biomass::scbi_stem_shrub_tiny
trees <- fgeo.biomass::scbi_stem_tree_tiny
data <- bind_rows(shrubs, trees)
equations <- data %>%
add_species(scbi_species, "scbi") %>%
allo_find(dbh_unit = "mm")
#> Adding `site`.
#> Overwriting `sp`; it now stores Latin species names.
#> Adding `rowid`.
#> * Matching equations by site and species.
#> * Refining equations according to dbh.
#> * Using generic equations where expert equations can't be found.
#> Warning: Can't find equations for 29 rows (inserting `NA`).
biomass <- equations %>%
allo_evaluate(dbh_unit = "mm")
#> Shrub `biomass` given for main stems only but applies to the whole shrub.
#> Guessing `dbh` in [mm]
#> You may provide the `dbh` unit manually via the argument `dbh_unit`.
#> Converting `dbh` based on `dbh_unit`.
#> `biomass` values are given in [kg].
#> Warning: Can't convert all units (inserting 29 missing values):
#> the 'from' argument is not an acceptable unit.
# Biomass given only for main stem but representes whole shrub biomass
with_biomass <- left_join(equations, biomass) %>%
select(1:6, dbh, biomass)
#> Joining, by = "rowid"
with_biomass
#> # A tibble: 46 x 8
#> rowid treeID stemID tag StemTag sp dbh biomass
#> <int> <dbl> <dbl> <dbl> <dbl> <chr> <dbl> <dbl>
#> 1 1 1111 1111 10133 1 lindera benzoin 50.9 5.56
#> 2 2 1111 32221 10133 2 lindera benzoin 18.5 NA
#> 3 3 1111 36962 10133 3 lindera benzoin 17.2 NA
#> 4 4 1111 38540 10133 4 lindera benzoin 17.2 NA
#> 5 5 1111 39225 10133 5 lindera benzoin 17.1 NA
#> 6 6 1111 39581 10133 6 lindera benzoin 15.9 NA
#> 7 7 2333 2333 20035 1 lindera benzoin 56.9 7.27
#> 8 8 2333 32434 20035 10 lindera benzoin 12.1 NA
#> 9 9 2333 37071 20035 11 lindera benzoin 15.9 NA
#> 10 10 2333 38598 20035 12 lindera benzoin 11.5 NA
#> # ... with 36 more rows
# More clearly showing whole-shrub biomass
left_join(equations, biomass) %>%
select(1:6, dbh, biomass) %>%
group_by(treeID, sp) %>%
summarise(whole_shrub_biomass = sum(biomass, na.rm = TRUE))
#> Joining, by = "rowid"
#> # A tibble: 10 x 3
#> # Groups: treeID [10]
#> treeID sp whole_shrub_biomass
#> <dbl> <chr> <dbl>
#> 1 509 fraxinus americana 497.
#> 2 1111 lindera benzoin 5.56
#> 3 2333 lindera benzoin 7.27
#> 4 5476 lindera benzoin 9.05
#> 5 12427 carpinus caroliniana 44.6
#> 6 13505 cercis canadensis 63.3
#> 7 22479 lindera benzoin 3.34
#> 8 25910 juglans nigra 564.
#> 9 28182 lindera benzoin 5.85
#> 10 28551 carya glabra 430. Created on 2019-04-03 by the reprex package (v0.2.1) |
Here I confirm what I commented at #41 (comment) diameter_at_base <- function(x) {
sqrt(sum(x^2, na.rm = TRUE))
}
# Same as
basal_diameter <- function(dbh) {
sqrt(sum(basal_area(dbh), na.rm = TRUE) / pi) * 2
}
basal_area <- function(dbh) {
pi / 4 * dbh^2
}
identical(basal_diameter(10), diameter_at_base(10))
#> [1] TRUE
random_dbh <- runif(10) * 100
random_dbh
#> [1] 7.409593 64.421704 25.298599 32.595740 78.228289 50.095644 29.966804
#> [8] 45.656978 15.480379 55.405035
identical(basal_diameter(random_dbh), diameter_at_base(random_dbh))
#> [1] TRUE Created on 2019-04-03 by the reprex package (v0.2.1) |
For shrub equations which independent variable is Which diameter does library(tidyverse)
allodb::master_tidy() %>%
filter(str_detect(equation_form, "dba")) %>%
select(equation_form, matches("min|max")) %>%
unique()
#> Joining `equations` and `sitespecies` by 'equation_id'; then `sites_info` by 'site'.
#> # A tibble: 18 x 3
#> equation_form dbh_min_cm dbh_max_cm
#> <chr> <dbl> <dbl>
#> 1 a*(dba^b) 0.18 4.31
#> 2 a*(dba^b) 0.12 0.69
#> 3 a*(dba^b) 0.2 1.2
#> 4 a*(dba^b) 0.3 0.9
#> 5 a*(dba^b) 0.28 1.59
#> 6 exp(a+b*log(dba)) 0.5 2.1
#> 7 exp(a+b*log(dba)) 0.6 2.5
#> 8 exp(a+b*log(dba)) 0.4 1.4
#> 9 exp(a+b*log(dba)) 0.6 3.6
#> 10 exp(a+b*log(dba)) 0.7 2.2
#> 11 exp(a+b*log(dba)) 0.1 1.1
#> 12 exp(a+b*log(dba)) 0.4 3.3
#> 13 exp(a+b*log(dba)) 0.4 11.5
#> 14 exp(a+b*log(dba)) 0.3 11.7
#> 15 exp(a+b*log(dba)) 0.3 6.5
#> 16 exp(a+b*log(dba)) 0.5 2.6
#> 17 a*(dba^b) 0.31 1.37
#> 18 a*(dba^b) 0.64 5.7 Created on 2019-04-03 by the reprex package (v0.2.1) |
I assume that |
Which diameter does dbh_min_cm refer to (in allodb)? Maybe I need to specify that for each equation that uses dba. I can do it in the 'notes' column (currently called warning but I will replace the column name with notes) |
Can you please extend a bit? Say that a single shrub has three stems, s1, s2, and s3, with dbh values dbh1 = 1cm, dbh2 = 2cm, and dbh3 = 3cm. The resulting basal diameter (accounts for all three stems together) is this: fgeo.biomass:::basal_diameter(c(1, 2, 3))
#> [1] 3.741657 Now, say that for this species of shrub, dbh_min = 3.5cm. Which statement is true: a. No stem can use this equation because no stem is 3.5cm or greater. |
For consistency, we now also distribute the biomass of shrubs which independent variable is Now, all stems (of valid library(tidyverse)
library(fgeo.biomass)
shrubs <- fgeo.biomass::scbi_stem_tiny_shrub
equations <- shrubs %>%
add_species(scbi_species, "scbi") %>%
allo_find(dbh_unit = "mm")
#> Adding `site`.
#> Overwriting `sp`; it now stores Latin species names.
#> Adding `rowid`.
#> * Matching equations by site and species.
#> * Refining equations according to dbh.
#> * Using generic equations where expert equations can't be found.
#> Warning: Can't find equations for 38 rows (inserting `NA`).
biomass <- equations %>%
allo_evaluate(dbh_unit = "mm")
#> Shrub `biomass` given for main stems only but applies to the whole shrub.
#> Guessing `dbh` in [mm]
#> You may provide the `dbh` unit manually via the argument `dbh_unit`.
#> Converting `dbh` based on `dbh_unit`.
#> `biomass` values are given in [kg].
left_join(equations, biomass) %>%
select(treeID, sp, eqn, dbh, matches("min|max"), biomass) %>%
group_by(treeID) %>%
mutate(n = sum(!is.na(biomass))) %>%
filter(n > 1) %>%
arrange(treeID, desc(biomass)) %>%
select(-n) %>%
print(n = Inf)
#> Joining, by = "rowid"
#> # A tibble: 32 x 7
#> # Groups: treeID [5]
#> treeID sp eqn dbh dbh_min_mm dbh_max_mm biomass
#> <dbl> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
#> 1 2333 lindera ben~ exp(-2.2118 + ~ 56.9 30 640 3.75
#> 2 2333 lindera ben~ exp(-2.2118 + ~ 55.2 30 640 3.53
#> 3 2333 lindera ben~ <NA> 12.1 NA NA NA
#> 4 2333 lindera ben~ <NA> 15.9 NA NA NA
#> 5 2333 lindera ben~ <NA> 11.5 NA NA NA
#> 6 2333 lindera ben~ <NA> 11.1 NA NA NA
#> 7 2333 lindera ben~ <NA> 22.5 NA NA NA
#> 8 2333 lindera ben~ <NA> 23.7 NA NA NA
#> 9 2333 lindera ben~ <NA> 13.8 NA NA NA
#> 10 2333 lindera ben~ <NA> 26 NA NA NA
#> 11 2333 lindera ben~ <NA> 12 NA NA NA
#> 12 2333 lindera ben~ <NA> 19.2 NA NA NA
#> 13 2333 lindera ben~ <NA> 14.7 NA NA NA
#> 14 3805 hamamelis v~ 38.111 * (dba^~ 23.5 1.8 43.1 0.0891
#> 15 3805 hamamelis v~ 38.111 * (dba^~ 16.8 1.8 43.1 0.0127
#> 16 3805 hamamelis v~ 38.111 * (dba^~ 15.7 1.8 43.1 0.00858
#> 17 3805 hamamelis v~ 38.111 * (dba^~ 15.4 1.8 43.1 0.00768
#> 18 3805 hamamelis v~ 38.111 * (dba^~ 14.8 1.8 43.1 0.00610
#> 19 3805 hamamelis v~ 38.111 * (dba^~ 12.7 1.8 43.1 0.00251
#> 20 3805 hamamelis v~ <NA> 94.2 NA NA NA
#> 21 3805 hamamelis v~ <NA> 82.6 NA NA NA
#> 22 5476 lindera ben~ exp(-2.2118 + ~ 62.3 30 640 5.05
#> 23 5476 lindera ben~ exp(-2.2118 + ~ 43.7 30 640 2.49
#> 24 5476 lindera ben~ exp(-2.2118 + ~ 34.1 30 640 1.51
#> 25 6275 hamamelis v~ 38.111 * (dba^~ 42.6 1.8 43.1 1.73
#> 26 6275 hamamelis v~ 38.111 * (dba^~ 18.4 1.8 43.1 0.0133
#> 27 6275 hamamelis v~ 38.111 * (dba^~ 14.6 1.8 43.1 0.00348
#> 28 8302 hamamelis v~ 38.111 * (dba^~ 16.7 1.8 43.1 0.0554
#> 29 8302 hamamelis v~ 38.111 * (dba^~ 14.9 1.8 43.1 0.0286
#> 30 8302 hamamelis v~ 38.111 * (dba^~ 10 1.8 43.1 0.00283
#> 31 8302 hamamelis v~ <NA> 51.3 NA NA NA
#> 32 8302 hamamelis v~ <NA> 49 NA NA NA Created on 2019-04-04 by the reprex package (v0.2.1) |
Here is a flowchart summary of the available code: |
Closing now. What remains unclear is now a separate issue |
Hi Mauro, I cannot see the flowchart summary here
|
Sorry, I hadn't made the link public. Here you go: https://drive.google.com/file/d/1HBHR4F3jkVDU9i_6s-rGdf7dWodbWYFh/view?usp=sharing https://drive.google.com/file/d/1MJkD7hp2XNFOYA3eMaoXgKGbOP0J3WXa/view?usp=sharing |
This issue is in relation to issue #38, about the use of dba (diameter at stem base) in shrub allometries.
I have summarized what I think is the correct way to present these calculations. I will need Mauro’s help to convert this into a function that depends only on DBH.
Problem (this paragraph can be included in the description of the function):
Most available equations to calculate shrub biomass in temperate regions (Smith et al 1983, Lutz et al, 2014, Halpern and Millet, 1996) use diameter at the base of the stem (15 cm above ground or close to ground) as independent variable. Given that at CTFS-ForestGEO plots the standardized diameter measurement for woody stems is at breast height (DBH, 1.37 m), we WROTE a function to use stem DBH as input to calculate biomass for some shrub species (see site.species table). We suggest the following:
Potential solution (where I need help)..
Step 1=Calculate the basal area contribution of each stem within a tree
BA <- (pi/4) * dataset$dbh^2
Step 2= Sum of basal area of each stem to get basal area of per tree
tree.sum.BA.un <- tapply(BA, dataset$tag, sum, na.rm = T)
Step 3= Calculate the contribution of each stem to sum of basal area of a tree
BA.contribution <- BA / tree.sum.BA
a) If an allometry equation use DBA (diameter at base) as independent variable then:
Step 4= calculate the diameter at the base of shrub, assuming area preserving
Step 5= calculate AGB using the basal diameter equation (a*(DBA^b) or exp(a+b*ln(DBA))
Step 6= Redistribute the biomass of the main stem to other stems, using the basal area contribution
b) If DBH is the independent variable in the equation (assuming that only the diameter of the main stem was measured in a shrub), then:
Step 4= identify the main stem (stem with the largest DBH).
Step 5= calculate AGB using DBH of main stem
Step 6= redistribute the biomass to other stems within the tree, using the basal contribution of each stem.
The text was updated successfully, but these errors were encountered: