Skip to content

Commit ac14dd0

Browse files
committed
Add dominant diameter #1
1 parent 033e4ed commit ac14dd0

File tree

9 files changed

+241
-22
lines changed

9 files changed

+241
-22
lines changed

NAMESPACE

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# Generated by roxygen2: do not edit by hand
22

33
export(eq_biomass_dieguez_aranda_2009)
4+
export(eq_biomass_manrique_2017)
45
export(eq_biomass_montero_2005)
56
export(eq_biomass_ruiz_peinado_2011)
67
export(eq_biomass_ruiz_peinado_2012)
78
export(eq_hd_vazquez_veloso_2025)
8-
export(eq_manrique_2017)
99
export(lid_fcov)
1010
export(lid_lhdi)
1111
export(plot)
@@ -26,6 +26,7 @@ export(silv_sample_size_stratified)
2626
export(silv_spacing_index)
2727
export(silv_sqrmean_diameter)
2828
export(silv_stand_basal_area)
29+
export(silv_stand_dominant_diameter)
2930
export(silv_stand_dominant_height)
3031
export(silv_stand_lorey_height)
3132
export(silv_stand_qmean_diameter)

NEWS.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
# silviculture 0.2.0 (dev)
2+
# silviculture 0.1.9000 (dev)
33

44
This new version brings new naming conventions that will be useful for sorting the package into "modules" of related functions.
55

@@ -17,6 +17,12 @@ The old functions are now deprecated and will be eliminated in a future release.
1717

1818
* `silv_predict_height()`: estimates height from diameter, using the so-called h-d curves. The argument `equation` allows to choose which equations to use. Currently, only `eq_hd_aitor2025()` available.
1919

20+
* `silv_stand_dominant_diameter()`: calculates dominant diameter using two methods:
21+
22+
- `Assman`: the mean diameter of the 100 thickest trees per hectare
23+
24+
- `Weise`: the quadratic mean diameter of the 20% thickest trees per hectare
25+
2026
* `eq_biomass_*()`: equations to be used inside the `model` argument of `silv_predict_biomass()`.
2127

2228
## Bug Fixes

R/deprecated-funs.R

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ silv_dominant_height <- function(diameter,
193193
.cumtrees = cumsum(nt),
194194
.nmax = which(.cumtrees >= 100)[1],
195195
.nmax = if (is.na(.nmax[1])) which.max(.cumtrees) else .nmax,
196-
.do = calc_dominant_height(.nmax, nt, h)
196+
.do = calc_dominant_metric(.nmax, nt, h)
197197
) |>
198198
dplyr::pull(.do)
199199
} else {
@@ -204,7 +204,7 @@ silv_dominant_height <- function(diameter,
204204
.cumtrees = cumsum(nt),
205205
.nmax = which(.cumtrees >= 100)[1],
206206
.nmax = if (is.na(.nmax[1])) which.max(.cumtrees) else .nmax,
207-
.do = calc_dominant_height(.nmax, nt, h)
207+
.do = calc_dominant_metric(.nmax, nt, h)
208208
) |>
209209
dplyr::pull(.do)
210210
}

R/metrics-stand-level.R

Lines changed: 102 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,32 +142,129 @@ silv_stand_dominant_height <- function(diameter,
142142
)
143143
}
144144

145-
146145
# 2. Calculate dominant height
147146
if (tolower(which) == "assman") {
148-
d0 <- data |>
147+
h0 <- data |>
149148
## sort descending by diameter class
150149
dplyr::arrange(dplyr::desc(d)) |>
151150
dplyr::mutate(
152151
.cumtrees = cumsum(nt),
153152
.nmax = which(.cumtrees >= 100)[1],
154153
.nmax = if (is.na(.nmax[1])) which.max(.cumtrees) else .nmax,
155-
.do = calc_dominant_height(.nmax, nt, h)
154+
.do = calc_dominant_metric(.nmax, nt, h)
156155
) |>
157156
dplyr::pull(.do)
158157
} else {
159-
d0 <- data |>
158+
h0 <- data |>
160159
## sort descending by height
161160
dplyr::arrange(dplyr::desc(h)) |>
162161
dplyr::mutate(
163162
.cumtrees = cumsum(nt),
164163
.nmax = which(.cumtrees >= 100)[1],
165164
.nmax = if (is.na(.nmax[1])) which.max(.cumtrees) else .nmax,
166-
.do = calc_dominant_height(.nmax, nt, h)
165+
.do = calc_dominant_metric(.nmax, nt, h)
167166
) |>
168167
dplyr::pull(.do)
169168
}
170169

170+
# 3. If it's not vectorized, retrieve just one value
171+
if (is.null(ntrees)) h0[1] else h0
172+
173+
}
174+
175+
176+
177+
178+
179+
#' Calculates the dominant diameter
180+
#'
181+
#' Calculates the dominant diameter using Assman and Friedrich method, or
182+
#' Weise method
183+
#'
184+
#' @param diameter Numeric vector with diameter classes
185+
#' @param ntrees Optional. Numeric vector with number of trees per hectare.
186+
#' Use this argument when you have aggregated data by diametric classes (see details).
187+
#' @param which The method to calculate the dominant diameter (see details)
188+
#' @param quiet if \code{TRUE}, messages will be supressed
189+
#'
190+
#' @details
191+
#' The dominant diameter \eqn{D_0} is the mean diameter of the 100 thickest trees per
192+
#' hectare. Therefore, `diameter` and `ntrees` should be vectors of the same length.
193+
#'
194+
#' - \bold{Assman}: calculates the \eqn{D_0} as the mean diameter of the 100 thickest
195+
#' trees per hectare
196+
#'
197+
#' - \bold{Weise}: calculates the \eqn{D_0} as the quadratic mean diameter of the
198+
#' 20% thickest trees per hectare
199+
#'
200+
#' @return A numeric vector
201+
#' @export
202+
#' @include utils-not-exported.R
203+
#'
204+
#' @examples
205+
#' ## calculate d0 for inventory data grouped by plot_id and species
206+
#' library(dplyr)
207+
#' inventory_samples |>
208+
#' mutate(dclass = silv_tree_dclass(diameter)) |>
209+
#' summarise(
210+
#' height = mean(height, na.rm = TRUE),
211+
#' ntrees = n(),
212+
#' .by = c(plot_id, species, dclass)
213+
#' ) |>
214+
#' mutate(
215+
#' ntrees_ha = silv_density_ntrees_ha(ntrees, plot_size = 10),
216+
#' d0 = silv_stand_dominant_diameter(dclass, ntrees_ha),
217+
#' .by = c(plot_id, species)
218+
#' )
219+
silv_stand_dominant_diameter <- function(diameter,
220+
ntrees = NULL,
221+
which = "assman",
222+
quiet = FALSE) {
223+
224+
# 0. Handle errors and setup
225+
## 0.1. Errors
226+
if (!tolower(which) %in% c("assman", "weise")) cli::cli_abort("`which` must be either <assman> or <weise>.")
227+
if (!is.numeric(diameter)) cli::cli_abort("`diameter` must be a numeric vector")
228+
## 0.2. Invalid values
229+
if (any(diameter <= 0, na.rm = TRUE)) cli::cli_warn("Any value in `diameter` is less than 0. Review your data.")
230+
231+
# 1. Create a data frame with input variables
232+
if (is.null(ntrees)) {
233+
data <- data.frame(
234+
d = diameter,
235+
nt = 1
236+
)
237+
} else {
238+
data <- data.frame(
239+
d = diameter,
240+
nt = ntrees
241+
)
242+
}
243+
244+
if (tolower(which) == "assman") {
245+
d0 <- data |>
246+
## sort descending by diameter class
247+
dplyr::arrange(dplyr::desc(d)) |>
248+
dplyr::mutate(
249+
.cumtrees = cumsum(nt),
250+
.nmax = which(.cumtrees >= 100)[1],
251+
.nmax = if (is.na(.nmax[1])) which.max(.cumtrees) else .nmax,
252+
.do = calc_dominant_metric(.nmax, nt, d)
253+
) |>
254+
dplyr::pull(.do)
255+
} else {
256+
n_tickest_trees <- 0.2 * sum(data$nt)
257+
d0 <- data |>
258+
## sort descending by diameter class
259+
dplyr::arrange(dplyr::desc(d)) |>
260+
dplyr::mutate(
261+
.cumtrees = cumsum(nt),
262+
nt_sel = calc_accumulated_trees(nt, .cumtrees, n_tickest_trees),
263+
.do = silv_stand_qmean_diameter(d, nt_sel)
264+
) |>
265+
dplyr::pull(.do)
266+
}
267+
171268
# 3. If it's not vectorized, retrieve just one value
172269
if (is.null(ntrees)) d0[1] else d0
173270

R/utils-not-exported.R

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11

22

3-
#' Calculates dominant height
3+
#' Calculates dominant height or dominant diameter
44
#'
55
#' @param nmax Index of first diametric class with > 100 trees; if there are no
66
#' 100 trees, it is the index of the maximum
77
#' @param ntress Number of trees per hectare
8-
#' @param height Height of the diametric class
8+
#' @param metric Height of the diametric class or diameter
9+
#' @param max_trees Number to trees to calculate dominant metric
910
#'
1011
#' @return A numeric vector
1112
#' @keywords internal
12-
calc_dominant_height <- function(nmax, ntress, height) {
13+
calc_dominant_metric <- function(nmax, ntress, metric, max_trees = 100) {
1314

1415
# initialize n and empty list
1516
n <- 0
@@ -20,14 +21,14 @@ calc_dominant_height <- function(nmax, ntress, height) {
2021
## sum previous trees plus new trees
2122
n <- n + ntress[i]
2223
## are we over 100 trees already?
23-
if (n > 100) {
24-
new_trees <- ntress[i] - n + 100
24+
if (n > max_trees) {
25+
new_trees <- ntress[i] - n + max_trees
2526
## add to list and exit loop
26-
l[[i]] <- c(new_trees, height[i])
27+
l[[i]] <- c(new_trees, metric[i])
2728
break
2829
} else {
2930
## add to list
30-
l[[i]] <- c(ntress[i], height[i])
31+
l[[i]] <- c(ntress[i], metric[i])
3132
}
3233
}
3334

@@ -46,6 +47,39 @@ calc_dominant_height <- function(nmax, ntress, height) {
4647

4748

4849

50+
#' Calculates number of trees until reaching a maximum number of trees
51+
#'
52+
#' @param ntrees Number of trees per hectare
53+
#' @param cumtrees Accumulated trees and sorted from thickest to thinner diameter
54+
#' @param max_trees Number to trees to calculate dominant metric
55+
#'
56+
#' @return A numeric vector
57+
#' @keywords internal
58+
calc_accumulated_trees <- function(ntrees, cumtrees, max_trees) {
59+
60+
## row with with accumulated max_trees
61+
row_with_target <- which(cumtrees >= max_trees)[1]
62+
63+
## calculate trees needed from each diameter class
64+
trees_needed <- rep(0, length(ntrees))
65+
66+
## for rows before the target row, take all trees
67+
if (row_with_target > 1) {
68+
trees_needed[1:(row_with_target-1)] <- ntrees[1:(row_with_target-1)]
69+
}
70+
71+
## for the target row, calculate remaining trees needed
72+
trees_from_previous <- ifelse(row_with_target == 1, 0, cumtrees[row_with_target-1])
73+
trees_needed[row_with_target] <- max_trees - trees_from_previous
74+
75+
## return
76+
return(trees_needed)
77+
}
78+
79+
80+
81+
82+
4983
#' Calculates weighted mean
5084
#'
5185
#' @param var An object containing the values whose weighted median is to be computed

R/zzz.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ utils::globalVariables(
1515
"h0",
1616
"n",
1717
"nt",
18+
"nt_sel",
1819
"ntrees",
1920
"ntrees_ha",
2021
"remaining_to_extract",

man/calc_accumulated_trees.Rd

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 8 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/silv_stand_dominant_diameter.Rd

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

0 commit comments

Comments
 (0)