This document outlines a simple function that calculates stand level SDI based on a path to a stdstk RDS file (derived from an FVS output database) and a path to the “maxSDIcodes.csv” that was aggregated from variant-specific FVS documents found online (currently it only has codes for CA and CO variants, since those are chosen for Sugarpine).

In this first step, simply state your paths. In this case, I used local paths, but the same principles should work for s3 and drive connections.

It is also necessary to state your variant, since the maxSDIcodes can change slightly from variant to variant.

stdstk_path <- 
  '/Users/eyackulic/Downloads/CR-StdStk.rds' 

maxSDI_path <- 
  '/Users/eyackulic/Downloads/MaxSDICodes.csv' 

variant <- 'CR'

Next, I declare the function that will take in these inputs and derive a stand level SDI value.

standSDI <- function(stdstk_path, maxSDI_path, variant){

  stdstk <-
    stdstk_path |> 
    readRDS() |>
    dplyr::mutate(Variant = variant)
  
  maxSDI <-
    maxSDI_path |>
    read.csv() |>
    dplyr::select(Name, MaxSDI, Variant) |>
    dplyr::rename(Species = Name)
  
    stdstk |>
    dplyr::left_join(maxSDI, by = c('Species', 'Variant')) |>
    dplyr::group_by(StandID,Year, MgmtID) |>
    dplyr::reframe(
      Species = Species,
      SumBA = LiveBA/sum(LiveBA),
      MaxSDI = MaxSDI,
      sdi_val = MaxSDI * SumBA)|>
    dplyr::ungroup() |>
    dplyr::group_by(StandID,Year, MgmtID) |>
    dplyr::mutate(StandSDI = round(sum(sdi_val, na.rm = T), digits = 0)) |>
    dplyr::select(StandID, Year, MgmtID, StandSDI) |>
    dplyr::distinct()
}

In this snippet, I run an example of the function and show the outputs for one Stand and MgmtID. This stand was chosen because it had multiple species per year in the stdstk file, making it an ideal candidate to test that the function is working properly.

sample <- standSDI(stdstk_path, maxSDI_path, variant = 'CR')

sample |> dplyr::filter(StandID %in% 10003 & MgmtID %in%'CMCC') |> data.frame()
##    StandID Year MgmtID StandSDI
## 1    10003 2025   CMCC      298
## 2    10003 2029   CMCC      297
## 3    10003 2030   CMCC      297
## 4    10003 2031   CMCC      284
## 5    10003 2035   CMCC      284
## 6    10003 2036   CMCC      284
## 7    10003 2040   CMCC      284
## 8    10003 2045   CMCC      284
## 9    10003 2050   CMCC      284
## 10   10003 2055   CMCC      284
## 11   10003 2060   CMCC      284

and here are the results of that same filter with the tree species ids preserved (line 82 commented out to show what is happening in the maths)

  stdstk <-
    stdstk_path |> 
    readRDS() |>
    dplyr::mutate(Variant = variant)
  
  maxSDI <-
    maxSDI_path |>
    read.csv() |>
    dplyr::select(Name, MaxSDI, Variant) |>
    dplyr::rename(Species = Name)
  
    stdstk |>
    dplyr::left_join(maxSDI, by = c('Species', 'Variant')) |>
    dplyr::group_by(StandID,Year, MgmtID) |>
    dplyr::reframe(
      Species = Species,
      SumBA = LiveBA/sum(LiveBA),
      MaxSDI = MaxSDI,
      sdi_val = MaxSDI * SumBA)|>
    dplyr::ungroup() |>
    dplyr::group_by(StandID,Year, MgmtID) |>
    dplyr::mutate(StandSDI = round(sum(sdi_val, na.rm = T), digits = 0)) |>
 #   dplyr::select(StandID, Year, MgmtID, StandSDI) |>
    dplyr::distinct() |> 
    dplyr::filter(StandID %in% 10003 & MgmtID %in%'CMCC') |> 
    data.frame()
##    StandID Year MgmtID Species     SumBA MaxSDI   sdi_val StandSDI
## 1    10003 2025   CMCC     2TN 0.2144003    348  74.61131      298
## 2    10003 2025   CMCC    QUEM 0.7855997    284 223.11031      298
## 3    10003 2029   CMCC     2TN 0.2042565    348  71.08126      297
## 4    10003 2029   CMCC    QUEM 0.7957435    284 225.99115      297
## 5    10003 2030   CMCC     2TN 0.2025007    348  70.47025      297
## 6    10003 2030   CMCC    QUEM 0.7974993    284 226.48980      297
## 7    10003 2031   CMCC    QUEM 1.0000000    284 284.00000      284
## 8    10003 2035   CMCC    QUEM 1.0000000    284 284.00000      284
## 9    10003 2036   CMCC    QUEM 1.0000000    284 284.00000      284
## 10   10003 2040   CMCC    QUEM 1.0000000    284 284.00000      284
## 11   10003 2045   CMCC    QUEM 1.0000000    284 284.00000      284
## 12   10003 2050   CMCC    QUEM 1.0000000    284 284.00000      284
## 13   10003 2055   CMCC    QUEM 1.0000000    284 284.00000      284
## 14   10003 2060   CMCC    QUEM 1.0000000    284 284.00000      284