10  Species Conservation Factor

The baseline management scenario in the Kuamut Project consists of two main management practices: Natural Forest Management (NFM) and Mosaic Plantings (MP), as described in Chapter 2 and Chapter 9. Both of these forest Management practices have a tree size logging limit; 40cm diameter at breast height (DBH) for NFM and 31 cm DBH for MP. In addition to these limits, both strata also have legal constraints over the species that may be harvested from the forest. Following consultation with Sabah forestry, we obtained two taxa lists relevant to each strata derived from the Wildlife Conservation Enactment 1997; this list is presented in Table 10.1. As MP is a more intensive management practice there are only 18 species and 17 genera protected. Conversely, NFM has significantly more with 258 protected species and 42 genera.

Table 10.1: Protected species and genera for each strata. Taxa are from the Wildlife Conservation Enactment 1997.

As we have adopted a remote sensing approach at a 30 m resolution for modelling biomass and timber volume, it is not possible to detect species composition at this scale. Therefore, it is necessary to deduct the proportion of the timber volume that is made up of protected taxa from baseline stock estimates and on-going forest growth.

In this target, we calculate the proportion of protected species for the forest plots that are present across both NFM and MP strata for all trees above the respective cutting limits.

In order to ensure conservatism, we opted to use genus rather than species to estimate the proportion of protected species. Although this may result in a predicted over-protection of species, the approach reduces any risk relating to species misidentification in the field.

Table 10.2 shows the proportion of Above Ground Carbon in protected taxa for each strata. We adopt these values to reduce both our baseline volume estimates (as calculated in Chapter 11 and Chapter 12) and ongoing forest growth estimates to ensure that only timber volume and ongoing-growth within merchantable timber is considered (see Chapter 17).

Table 10.2: Species conservation factors as shown in the protected AGC (%) column. Note that we have conservatively based our calculations on botanical information to the genus rather than species level to reduce potential identification errors (individual species in the genera involved can be difficult to distinguish). The protected taxa list for the Mosaic areas comprises 18 species from 17 genera; the protected taxa list for the NFM areas comprises 258 species from 42 genera.

10.1 Code

Species conservation factor calculation code from R/protected-trees-stats.R
#' @title unique values of vector without NA
#' @description returns unique values of a vector without NA
#' @param x a vector
uniq_no_na <- function(x) unique(x[!is.na(x)])

#' @title get protected trees
#' @description get the protected trees from plot data based on a protected
#' species dataframe.
#' @param trees a dataframe of tree metrics
#' @param protected a dataframe of protected species
#' @param strata a string of the strata name to add as a column
#' @return a list of filtered trees and a summary of the protected trees
get_protected <- function(
    trees, protected, strata) {
  filt_trees <- trees |>
    dplyr::filter(
      Genus %in% protected$Genus
    )

  strat_stats <- filt_trees |>
    dplyr::summarise(pt = sum(AGC)) |>
    dplyr::mutate(
      at = dplyr::summarise(trees, at = sum(AGC))$at,
      pdiff = pt / at * 100
    ) |>
    dplyr::rename(
      `Protected Tree AGC (Mg)` = pt,
      `Harvestable Tree AGC (Mg)` = at,
      `protected AGC (%)` = pdiff
    ) |>
    dplyr::mutate(dplyr::across(everything(), \(x) round(x)),
      Strata = strata,
      `sp. conservation factor` = `protected AGC (%)` * 2
    ) |>
    dplyr::select(
      Strata, `Harvestable Tree AGC (Mg)`,
      `Protected Tree AGC (Mg)`, `protected AGC (%)`
    )

  return(list(filt_trees = filt_trees, strat_stats = strat_stats))
}


#' @title build species conservation factor table for book
#' @description build a table for the book that shows the species conservation
#' factor
#' @param df a dataframe of species conservation factor
#' @param ps_mosaic a dataframe of protected species in the mosaic areas
#' @param ps_all a dataframe of protected species in all areas
#' @return a gt table
build_sp_con_table <- function(
    df, ps_mosaic, ps_all, save = FALSE,
    header = TRUE, footnote = TRUE) {
  tab <- gt::gt(df, rowname_col = "Genus")
  if (header) {
    tab <- tab |>
      gt::tab_header(
        title = "Species Conservation Factor",
        subtitle = "Above Ground Carbon (AGC) in protected vs all tree species
      above cutting limit",
      )
  }
  if (footnote) {
    tab <- tab |>
      gt::tab_footnote(
        footnote = sprintf(
          "Note that we have used genus rather than species for calculting the
        proportion of protected taxa. This ensures conservativism by reducing
        the risk of misclassification in our survey plots.
        The protected taxa list for the Mosaic areas comprises %s species
      from %s genera; the protected taxa list for the NFM areas comprises % s
      species from %s genera.",
          length(uniq_no_na(ps_mosaic$gensp)),
          length(uniq_no_na(ps_mosaic$Genus)),
          length(uniq_no_na(ps_all$gensp)),
          length(uniq_no_na(ps_all$Genus))
        ),
        locations = gt::cells_column_labels(
          columns = (`protected AGC (%)`)
        )
      )
  }
  if (save) {
    tab_path <- set_path("Routputs/Tables")
    prot_sp_tab.doc <- file.path(tab_path, "protected-trees-stats-tab.docx")
    gt::gtsave(tab, file = prot_sp_tab.doc)
  }

  return(tab)
}

#' @title calculate species conservation factor
#' @description calculate the species conservation factor across NFM and Mosaic
#' areas
#' @param tree_mets a dataframe of tree metrics
#' @param plot_locs an sf object of plot locations
#' @param strata an sf object of strata
calc_sp_conserv_factor <- function(
    tree_mets, plot_locs, strata,
    prot_taxa) {
  tree_mets <- vroom::vroom(tree_mets)
  plot_locs <- sf::read_sf(plot_locs)
  strata <- sf::read_sf(strata)

  ps_all <- vroom::vroom(prot_taxa)
  ps_mosaic <- ps_all |>
    dplyr::filter(mgmt_strata == "Mosaic & NFM")

  plot_strat_join <- sf::st_join(plot_locs, strata) |>
    dplyr::select(PlotNo = Pl, mgmt_strata) |>
    sf::st_drop_geometry()

  tree_mets <- dplyr::left_join(
    tree_mets, plot_strat_join,
    by = "PlotNo", relationship = "many-to-many"
  )


  # --- establish subset of relevant trees
  trees_subset <- tree_mets |>
    dplyr::group_by(TreeID) |>
    dplyr::summarise(
      Genus = dplyr::first(Genus),
      Species = dplyr::first(Species),
      mgmt_strata = dplyr::first(mgmt_strata),
      DBH = max(DBH),
      AGC = max(AGC)
    ) |>
    dplyr::mutate(
      Species = dplyr::case_when(is.na(Species) ~ "sp", TRUE ~ Species),
      Genus = dplyr::case_when(is.na(Genus) ~ "gn", TRUE ~ Genus),
      gensp = paste(Genus, Species, sep = " ")
    )

  # --- get surveyed protected trees and get summaries


  nfm_trees_subset <- trees_subset |>
    dplyr::filter(
      mgmt_strata == "NFMCoupesGo",
      DBH > 40
    )

  mosaic_trees_subset <- trees_subset |>
    dplyr::filter(
      mgmt_strata %in% c("MosaicCoupesGo", "MosaicUNplanted"),
      DBH > 31
    )

  prot_gen_nfm <- get_protected(nfm_trees_subset, ps_all, "NFM")

  prot_gen_mosaic <- get_protected(mosaic_trees_subset, ps_mosaic, "Mosaic")

  prot_gen_strata <- dplyr::bind_rows(
    prot_gen_nfm$strat_stats,
    prot_gen_mosaic$strat_stats
  )

  book_tab <- build_sp_con_table(prot_gen_strata, ps_mosaic, ps_all,
    save = TRUE
  )

  spc <- prot_gen_strata |>
    dplyr::select(Strata, spcf = `protected AGC (%)`) |>
    dplyr::mutate(spcf = 1 - spcf / 100)

  nfm_spc <- spc |>
    dplyr::filter(Strata == "NFM") |>
    dplyr::pull(spcf)

  mosaic_spc <- spc |>
    dplyr::filter(Strata == "Mosaic") |>
    dplyr::pull(spcf)


  return(list(
    n_surv_mos_prot = nrow(prot_gen_mosaic$filt_trees),
    n_surv_nfm_prot = nrow(prot_gen_nfm$filt_trees),
    spc_nfm = nfm_spc,
    spc_mosaic = mosaic_spc,
    spc_tab_pretty = prot_gen_strata
  ))
}