Skip to content
Snippets Groups Projects
biocol.R 27.4 KiB
Newer Older
Jannes Breier's avatar
Jannes Breier committed
# written by Fabian Stenzel
# 2022-2023 - stenzel@pik-potsdam.de

################# BioCol calc functions  ###################

#' Calculate BioCol based on file lists from a PNV run and LU run of LPJmL.
#' Do not use this function directly, unless you are instructed to do so, there
#' is a wrapper called calc_biocol() which is for use of endusers.
Jannes Breier's avatar
Jannes Breier committed
#'
#' Function to calculate BioCol based on a PNV run and LU run of LPJmL
#' @param files_scenario list with variable names and corresponding file paths
#' (character string) of the scenario LPJmL run. All needed files are
#' provided in XXX. E.g.: list(npp = "/temp/npp.bin.json")
#' @param files_baseline list with variable names and corresponding file paths
#' (character string) of the baseline LPJmL run. All needed files are
#' provided in XXX. E.g.: list(npp = "/temp/npp.bin.json"). If not
Jannes Breier's avatar
Jannes Breier committed
#' needed for the applied method, set to NULL.
#' @param files_reference list with npp file path (character string) of the
#' reference LPJmL run (usually Holocene/preindustrial).
#' E.g.: list(npp = "/temp/npp.bin.json"). If NULL uses baseline npp.
Jannes Breier's avatar
Jannes Breier committed
#' @param time_span_scenario time span to be used for the scenario run, defined
#' as a character vector, e.g. `as.character(1982:2011)` (required)
#' @param time_span_baseline time span to be used for the baseline run, defined
#' as a character vector, e.g. `as.character(1901:1930)`. Can differ in offset
Jannes Breier's avatar
Jannes Breier committed
#' and length from `time_span_scenario`! If `NULL` value of `time_span_scenario`
#' is used
#' @param time_span_reference time span to read reference npp from, using
Jannes Breier's avatar
Jannes Breier committed
#'     index years 10:39 from potential npp input if set to NULL (default: NULL)
#' @param gridbased logical are pft outputs gridbased or pft-based?
#' @param read_saved_data flag whether to read previously saved data
#'        instead of reading it in from output files (default FALSE)
#' @param save_data whether to save input data to file (default FALSE)
#' @param data_file file to save/read input data to/from (default NULL)
#' @param include_fire boolean include firec in calculation of BioCol?
#' (default TRUE)
#' @param external_fire instead of reading in firec for fire emissions, read in
#'        this external firec file from a separate spitfire run with disabled
#'        lighning. this will then include only human induced fires
#' (default FALSE)
#' @param external_wood_harvest include external wood harvest from LUH2_v2h
#'        (default FALSE)
#' @param grass_scaling whether to scale pasture harvest according to
#'        data given via grass_harvest_file (default FALSE)
#' @param npp_threshold lower threshold for npp (to mask out non-lu areas
#'        according to Haberl et al. 2007). Below BioCol will be set to 0.
#'        (default: 20 gC/m2)
#' @param epsilon minimum value for npp, below which it will be set to 0
Jannes Breier's avatar
Jannes Breier committed
#' @param grass_harvest_file file containing grazing data to rescale the
#'        grassland harvests according to Herrero et al. 2013. File contains:
#'        grazing_data list object with $name and $id of 29 world regions, and
#'        $Herrero_2000_kgDM_by_region containing for each of these regions and
#'        mapping_lpj67420_to_grazing_regions array with a mapping between 67420
#'        LPJmL cells and the 29 regions
#' @param external_fire_file path to external file with human induced fire
#'        fraction c(cell,month,year) since 1500
#' @param external_wood_harvest_file path to R-file containing processed
#'        timeline of maps for LUH2_v2h woodharvest
#' @param suppress_warnings suppress warnings when reading files (default: TRUE)
Jannes Breier's avatar
Jannes Breier committed
#'
#' @return list data object containing BioCol and components as arrays:
#'         biocol_overtime, biocol_overtime_abs, biocol_overtime_abs_frac_piref,
#'         biocol_overtime_abs_frac, biocol_overtime_pos,
#'         biocol_overtime_pos_frac_piref,biocol_overtime_pos_frac,
#'         biocol_overtime_frac_piref, biocol_overtime_frac, npp_harv_overtime,
#'         npp_luc_overtime,npp_act_overtime, npp_pot_overtime,npp_eco_overtime,
#'         harvest_grasslands_overtime, harvest_bioenergy_overtime,
#'         harvest_cft_overtime, rharvest_cft_overtime, fire_overtime,
#'         timber_harvest_overtime, wood_harvest_overtime, biocol, biocol_frac,
#'         npp, biocol_frac_piref, npp_potential, npp_ref, harvest_cft,
#'         rharvest_cft, biocol_harvest, biocol_luc, lat, lon, cellarea
Jannes Breier's avatar
Jannes Breier committed
#'
#' @export
Jannes Breier's avatar
Jannes Breier committed
read_calc_biocol <- function(
    # nolint
    files_scenario,
    files_baseline,
    files_reference = NULL,
    time_span_scenario,
    time_span_baseline = NULL,
    time_span_reference = NULL,
    gridbased = TRUE,
    read_saved_data = FALSE,
    save_data = FALSE,
    data_file = NULL,
    include_fire = FALSE,
    external_fire = FALSE,
    external_wood_harvest = FALSE,
    grass_scaling = FALSE,
    npp_threshold = 20,
    epsilon = 0.001, # gC/m2
    grass_harvest_file = NULL,
    external_fire_file = NULL,
Fabian Stenzel's avatar
Fabian Stenzel committed
    external_wood_harvest_file = NULL,
    suppress_warnings = TRUE) {
Jannes Breier's avatar
Jannes Breier committed
  if (is.null(files_reference)) {
    files_reference <- list(npp = baseline_npp_file)
Jannes Breier's avatar
Jannes Breier committed
  }
  if (is.null(time_span_baseline)) {
    time_span_baseline <- time_span_scenario
Jannes Breier's avatar
Jannes Breier committed
  }
  if (is.null(time_span_reference)) {
    time_span_reference <- time_span_scenario[3:12]
  }
Jannes Breier's avatar
Jannes Breier committed
  if (grass_scaling && !file.exists(grass_harvest_file)) {
    stop(
Jannes Breier's avatar
Jannes Breier committed
      paste0("Grass harvest scaling enabled, but grass_harvest_file \
              does not exist in: ", grass_harvest_file)
Jannes Breier's avatar
Jannes Breier committed
    )
  }
  if (external_wood_harvest && !file.exists(external_wood_harvest_file)) {
    stop(
      paste0("External wood harvest enabled, but external_wood_harvest_file \
              does not exist in: ", external_wood_harvest_file)
Jannes Breier's avatar
Jannes Breier committed
    )
  }
  if (external_fire && !file.exists(external_fire_file)) {
    stop(
      paste0("External fire fraction file enabled, but external_fire_file \
              does not exist in: ", external_fire_file)
Jannes Breier's avatar
Jannes Breier committed
    )
  }
  # reading required data
  if (read_saved_data) {
    if (file.exists(data_file)) {
Jannes Breier's avatar
Jannes Breier committed
      message("Reading in data from previously saved data file")
Jannes Breier's avatar
Jannes Breier committed
      load(data_file)
      wood_harvest[is.na(wood_harvest)] <- 0
    } else {
      stop(
Jannes Breier's avatar
Jannes Breier committed
        paste0(
          "data_file: '",
          data_file,
          "' does not exist but is required since reading is set to FALSE."
        )
Jannes Breier's avatar
Jannes Breier committed
      )
    }
    if (save_data) {
      save_data <- FALSE
Jannes Breier's avatar
Jannes Breier committed
      message(
        "Both read_saved_data and save_data have been set to TRUE. ",
        "Overwriting with the same data does not make sense, saving ",
        "disabled. "
Jannes Breier's avatar
Jannes Breier committed
      )
    }
  } else {
Jannes Breier's avatar
Jannes Breier committed
    message("Reading in data from outputs")
Jannes Breier's avatar
Jannes Breier committed

    file_type <- tools::file_ext(files_baseline$grid)
Jannes Breier's avatar
Jannes Breier committed

    if (file_type %in% c("json", "clm")) {
      # read grid
      grid <- lpjmlkit::read_io(
Fabian Stenzel's avatar
Fabian Stenzel committed
      ) %>% suppressWarnings()
Jannes Breier's avatar
Jannes Breier committed
      # calculate cell area
      cellarea <- drop(lpjmlkit::read_io(
        filename = files_baseline$terr_area
Fabian Stenzel's avatar
Fabian Stenzel committed
      )$data) %>% suppressWarnings() # in m2
Jannes Breier's avatar
Jannes Breier committed
      lat <- grid$data[, , 2]
      lon <- grid$data[, , 1]

Jannes Breier's avatar
Jannes Breier committed
        files_scenario$npp,
Jannes Breier's avatar
Jannes Breier committed
        subset = list(year = as.character(time_span_scenario))
      ) %>%
Jannes Breier's avatar
Jannes Breier committed
        lpjmlkit::transform(to = c("year_month_day")) %>%
Jannes Breier's avatar
Jannes Breier committed
        lpjmlkit::as_array(aggregate = list(month = sum)) %>%
        # drop() %>% suppressWarnings()
        suppressWarnings(), drop = "band") # gC/m2
Jannes Breier's avatar
Jannes Breier committed
      npp[npp < epsilon] <- 0
Jannes Breier's avatar
Jannes Breier committed

      if (!is.null(files_reference)) {
        npp_ref <- abind::adrop(lpjmlkit::read_io(
Jannes Breier's avatar
Jannes Breier committed
          subset = list(year = as.character(time_span_reference))
        ) %>%
Jannes Breier's avatar
Jannes Breier committed
          lpjmlkit::transform(to = c("year_month_day")) %>%
Jannes Breier's avatar
Jannes Breier committed
          lpjmlkit::as_array(aggregate = list(month = sum)) %>%
          # drop() %>% suppressWarnings()
Jannes Breier's avatar
Jannes Breier committed
        npp_ref[npp_ref < epsilon] <- 0
Jannes Breier's avatar
Jannes Breier committed
      }

      pftnpp <- lpjmlkit::read_io(
        files_scenario$pft_npp,
Jannes Breier's avatar
Jannes Breier committed
        subset = list(year = as.character(time_span_scenario))
      ) %>%
Jannes Breier's avatar
Jannes Breier committed
        lpjmlkit::transform(to = c("year_month_day")) %>%
Jannes Breier's avatar
Jannes Breier committed
        lpjmlkit::as_array(aggregate = list(month = sum)) %>%
        suppressWarnings()
Jannes Breier's avatar
Jannes Breier committed
      pftnpp[pftnpp < epsilon] <- 0
Jannes Breier's avatar
Jannes Breier committed

      harvest <- lpjmlkit::read_io(
        files_scenario$pft_harvestc,
Jannes Breier's avatar
Jannes Breier committed
        subset = list(year = as.character(time_span_scenario))
      ) %>%
Jannes Breier's avatar
Jannes Breier committed
        lpjmlkit::transform(to = c("year_month_day")) %>%
Jannes Breier's avatar
Jannes Breier committed
        lpjmlkit::as_array(aggregate = list(month = sum)) %>%
        suppressWarnings()
Jannes Breier's avatar
Jannes Breier committed

      rharvest <- lpjmlkit::read_io(
        files_scenario$pft_rharvestc,
Jannes Breier's avatar
Jannes Breier committed
        subset = list(year = as.character(time_span_scenario))
      ) %>%
Jannes Breier's avatar
Jannes Breier committed
        lpjmlkit::transform(to = c("year_month_day")) %>%
Jannes Breier's avatar
Jannes Breier committed
        lpjmlkit::as_array(aggregate = list(month = sum)) %>%
        suppressWarnings()
Jannes Breier's avatar
Jannes Breier committed

      timber <- abind::adrop(lpjmlkit::read_io(
Jannes Breier's avatar
Jannes Breier committed
        files_scenario$timber_harvestc,
Jannes Breier's avatar
Jannes Breier committed
        subset = list(year = as.character(time_span_scenario))
      ) %>%
Jannes Breier's avatar
Jannes Breier committed
        lpjmlkit::transform(to = c("year_month_day")) %>%
Jannes Breier's avatar
Jannes Breier committed
        lpjmlkit::as_array(aggregate = list(month = sum)) %>%
        # drop() %>%
Jannes Breier's avatar
Jannes Breier committed

      if (include_fire) {
        # read fire in monthly res. if possible, then multiply with monthly
        # human/total ignition frac and aggregate to yearly. Otherwise aggregate
        # human/total ignition frac to yearly and multiply with yearly firec
        fire_raw <- lpjmlkit::read_io(
          files_scenario$firec,
Jannes Breier's avatar
Jannes Breier committed
          subset = list(year = as.character(time_span_scenario))
        ) %>%
Jannes Breier's avatar
Jannes Breier committed
          lpjmlkit::transform(to = c("year_month_day")) %>%
          lpjmlkit::as_array(aggregate = list(band = sum)) %>%
          # drop() %>%
Jannes Breier's avatar
Jannes Breier committed

        if (external_fire) {
          load(external_fire_file) # frac = c(cell,month,year)
        }

        if ("month" %in% names(dim(fire_raw))) {
          if (external_fire) {
            fire <- apply(
              fire_raw *
                lpjmlkit::asub(frac,
                  year = time_span_scenario,
                  drop = FALSE
                ),
              c("cell", "year"),
              sum,
              na.rm = TRUE
            ) # gC/m2
Jannes Breier's avatar
Jannes Breier committed
            rm(frac)
          } else {
            fire <- apply(
              fire_raw,
              c("cell", "year"),
              sum,
              na.rm = TRUE
            ) # gC/m2
          }
          rm(fire_raw)
        } else {
          if (external_fire) {
            frac_yearly <- apply(
              lpjmlkit::asub(frac,
                year = time_span_scenario,
                drop = FALSE
              ),
              c("cell", "year"),
              mean,
              na.rm = TRUE
Jannes Breier's avatar
Jannes Breier committed
            fire <- fire_raw * frac_yearly
            rm(frac_yearly, frac)
          }
        }
        gc()
      } else {
        fire <- timber * 0
      }

      if (external_wood_harvest) {
        load(external_wood_harvest_file) # wh_lpj in kgC
Jannes Breier's avatar
Jannes Breier committed
        # from kgC to gC/m2
        wood_harvest <- (
          lpjmlkit::asub(wh_lpj, year = time_span_scenario, drop = FALSE) *
            10^3 / cellarea
Jannes Breier's avatar
Jannes Breier committed
        )
        # the division can lead to NAs
        wood_harvest[is.na(wood_harvest)] <- 0
Jannes Breier's avatar
Jannes Breier committed
        gc()
      } else {
        wood_harvest <- fire * 0
      }

      cftfrac <- lpjmlkit::read_io(
        files_scenario$cftfrac,
Jannes Breier's avatar
Jannes Breier committed
        subset = list(year = as.character(time_span_scenario))
      ) %>%
Jannes Breier's avatar
Jannes Breier committed
        lpjmlkit::transform(to = c("year_month_day")) %>%
Jannes Breier's avatar
Jannes Breier committed
        lpjmlkit::as_array(aggregate = list(month = sum)) %>%
        suppressWarnings()
Jannes Breier's avatar
Jannes Breier committed

      npp_potential <- abind::adrop(lpjmlkit::read_io(
Jannes Breier's avatar
Jannes Breier committed
        subset = list(year = as.character(time_span_baseline))
      ) %>%
Jannes Breier's avatar
Jannes Breier committed
        lpjmlkit::transform(to = c("year_month_day")) %>%
Jannes Breier's avatar
Jannes Breier committed
        lpjmlkit::as_array(aggregate = list(month = sum)) %>%
        # drop() %>% suppressWarnings()
        suppressWarnings(), drop = "band") # gC/m2
Jannes Breier's avatar
Jannes Breier committed
      npp_potential[npp_potential < epsilon] <- 0
Jannes Breier's avatar
Jannes Breier committed

      fpc <- lpjmlkit::read_io(
        files_scenario$fpc,
Jannes Breier's avatar
Jannes Breier committed
        subset = list(year = as.character(time_span_scenario))
      ) %>%
Jannes Breier's avatar
Jannes Breier committed
        lpjmlkit::transform(to = c("year_month_day")) %>%
        lpjmlkit::as_array(subset = list(band = "natural stand fraction")) %>%
Fabian Stenzel's avatar
Fabian Stenzel committed
        suppressWarnings()
Jannes Breier's avatar
Jannes Breier committed

      pftbands <- lpjmlkit::read_meta(files_scenario$fpc)$nbands - 1
    } else if (file_type == "nc") { # to be added
      stop(
        "nc reading has not been updated to latest functionality.",
        " Please contact Fabian Stenzel"
      )
    } else {
Jannes Breier's avatar
Jannes Breier committed
      stop(
        "Unrecognized file type (",
        file_type,
        ")"
      )
Jannes Breier's avatar
Jannes Breier committed
    }

    bp_bands <- c(15, 16, 31, 32)
    grass_bands <- c(14, 30)
Jannes Breier's avatar
Jannes Breier committed
    nat_bands <- seq_len(pftbands)
Jannes Breier's avatar
Jannes Breier committed

    if (!gridbased) { # needs to be scaled with standfrac
      pftnpp[, , nat_bands] <- lpjmlkit::asub(pftnpp,
        band = nat_bands,
        drop = FALSE
      ) *
        lpjmlkit::asub(fpc, band = rep(
          "natural stand fraction",
          pftbands
        ), drop = FALSE)
      pftnpp[, , -c(nat_bands)] <- lpjmlkit::asub(pftnpp,
        band = -c(nat_bands),
        drop = FALSE
      ) * cftfrac
Jannes Breier's avatar
Jannes Breier committed
      harvest <- harvest * cftfrac
      rharvest <- rharvest * cftfrac
Jannes Breier's avatar
Jannes Breier committed
    }

    pftnpp_grasslands <- apply(
      lpjmlkit::asub(pftnpp, band = (pftbands + grass_bands), drop = FALSE),
      c("cell", "year"),
Jannes Breier's avatar
Jannes Breier committed
      sum
Jannes Breier's avatar
Jannes Breier committed
    ) # gC/m2 only from grassland bands
Jannes Breier's avatar
Jannes Breier committed

    pftnpp_cft <- apply(
        band = -c(nat_bands, pftbands + grass_bands, pftbands + bp_bands),
        drop = FALSE
      ),
      c("cell", "year"),
Jannes Breier's avatar
Jannes Breier committed
    ) # gC/m2 not from grassland and bioenergy bands
Jannes Breier's avatar
Jannes Breier committed

    pftnpp_bioenergy <- apply(
      lpjmlkit::asub(pftnpp, band = pftbands + bp_bands, drop = FALSE),
      c("cell", "year"),
Jannes Breier's avatar
Jannes Breier committed
      sum
Jannes Breier's avatar
Jannes Breier committed
    ) # gC/m2 only from bioenergy bands
Jannes Breier's avatar
Jannes Breier committed

    pftnpp_nat <- apply(
      lpjmlkit::asub(pftnpp, band = nat_bands, drop = FALSE),
      c("cell", "year"),
Jannes Breier's avatar
Jannes Breier committed
    ) # gC/m2
Jannes Breier's avatar
Jannes Breier committed

Jannes Breier's avatar
Jannes Breier committed
    if (is.null(files_reference)) {
Jannes Breier's avatar
Jannes Breier committed
      pi_window <- 3:32
      npp_ref <- lpjmlkit::asub(npp_potential, year = pi_window, drop = FALSE)
Jannes Breier's avatar
Jannes Breier committed
    } # npp_ref

    # lpjmlkit::asub(INARRAY, band = BANDS, drop = FALSE)
Jannes Breier's avatar
Jannes Breier committed
    harvest_grasslands <- apply(
      lpjmlkit::asub(harvest, band = grass_bands, drop = FALSE),
      c("cell", "year"),
Jannes Breier's avatar
Jannes Breier committed
      sum
    ) # gC/m2 only from grassland bands

    harvest_bioenergy <- apply(
      lpjmlkit::asub(harvest, band = bp_bands, drop = FALSE),
      c("cell", "year"),
Jannes Breier's avatar
Jannes Breier committed
      sum
    ) # gC/m2 only from bioenergy bands

    harvest_cft <- apply(
      lpjmlkit::asub(harvest, band = -c(grass_bands, bp_bands), drop = FALSE),
      c("cell", "year"),
Jannes Breier's avatar
Jannes Breier committed
      sum
    ) # gC/m2 not from grassland and bioenergy bands

    rharvest_cft <- apply(
      lpjmlkit::asub(rharvest, band = -c(grass_bands, bp_bands), drop = FALSE),
      c("cell", "year"),
Jannes Breier's avatar
Jannes Breier committed
      sum
    ) # gC/m2 not from grassland and bioenergy bands

    if (save_data) {
      if (!file.exists(data_file)) {
Jannes Breier's avatar
Jannes Breier committed
        message("Writing data file: ", data_file)
Jannes Breier's avatar
Jannes Breier committed
      } else {
Jannes Breier's avatar
Jannes Breier committed
        message(
          "Data file (",
          data_file,
          ") already exists, old file renamed to: ",
          data_file,
          "_sav"
Jannes Breier's avatar
Jannes Breier committed
        )
Jannes Breier's avatar
Jannes Breier committed
        file.rename(data_file, paste0(data_file, "_sav"))
      }

      save(npp_potential,
Jannes Breier's avatar
Jannes Breier committed
        npp,
        npp_ref,
        pftnpp_cft,
        pftnpp_nat,
        pftnpp_grasslands,
        pftnpp_bioenergy,
        harvest_cft,
        rharvest_cft,
        fire,
        timber,
        fpc,
        cftfrac,
        harvest_grasslands,
        harvest_bioenergy,
        wood_harvest,
        lat,
        lon,
        cellarea,
        file = data_file
      )
Jannes Breier's avatar
Jannes Breier committed
  message("Calculating data")
Jannes Breier's avatar
Jannes Breier committed

  if (grass_scaling) {
    load(grass_harvest_file)

    nregs <- length(grazing_data$name)

    lpj_grass_harvest_region <- array(0, dim = nregs)

    lpj_grass_harvest_2000 <- rowMeans(
Jannes Breier's avatar
Jannes Breier committed
      harvest_grasslands[, (1995 - start_year + 1):(2005 - start_year + 1)]
Jannes Breier's avatar
Jannes Breier committed
    ) * cellarea / 1000 * 2 # from gC/m2 to kgDM

    grassland_scaling_factor_cellwise <- array(1, dim = grid$ncells)

Jannes Breier's avatar
Jannes Breier committed
    for (r in seq_len(nregs)) {
Jannes Breier's avatar
Jannes Breier committed
      lpj_grass_harvest_region[r] <- sum(
        lpj_grass_harvest_2000[which(mapping_lpj67420_to_grazing_regions == r)]
      )
    }

    scaling_factor <- (
      grazing_data$Herrero_2000_kgDM_by_region / lpj_grass_harvest_region
    )

Jannes Breier's avatar
Jannes Breier committed
    for (r in seq_len(nregs)) {
Jannes Breier's avatar
Jannes Breier committed
      grassland_scaling_factor_cellwise[
        which(mapping_lpj67420_to_grazing_regions == r)
      ] <- scaling_factor[r]
    }
    harvest_grasslands <- harvest_grasslands * rep(
      grassland_scaling_factor_cellwise,
      times = length(harvest_grasslands[1, ])
    )
  }

  npp_act_overtime <- colSums(npp * cellarea) / 10^15 # gC/m2 to GtC
  npp_pot_overtime <- colSums(npp_potential * cellarea) / 10^15 # gC/m2 to GtC
  npp_eco_overtime <- colSums(pftnpp_nat * cellarea) / 10^15 # gC/m2 to GtC
  npp_luc_overtime <- npp_pot_overtime - npp_act_overtime

  harvest_cft_overtime <- colSums(
    harvest_cft * cellarea
  ) / 10^15 # gC/m2 to GtC
  rharvest_cft_overtime <- colSums(
    rharvest_cft * cellarea
  ) / 10^15 # gC/m2 to GtC
  harvest_grasslands_overtime <- colSums(
    harvest_grasslands * cellarea
  ) / 10^15 # gC/m2 to GtC
  harvest_bioenergy_overtime <- colSums(
    harvest_bioenergy * cellarea
  ) / 10^15 # gC/m2 to GtC

  timber_harvest_overtime <- colSums(
    timber * cellarea
  ) / 10^15 # gC/m2 to GtC
  fire_overtime <- colSums(
    fire * cellarea
  ) / 10^15 # gC/m2 to GtC
  wood_harvest_overtime <- colSums(
    wood_harvest * cellarea
  ) / 10^15 # gC/m2 to GtC

  if (include_fire) {
    npp_harv_overtime <- harvest_cft_overtime + rharvest_cft_overtime +
Jannes Breier's avatar
Jannes Breier committed
      harvest_grasslands_overtime + harvest_bioenergy_overtime +
      timber_harvest_overtime + fire_overtime + wood_harvest_overtime
Jannes Breier's avatar
Jannes Breier committed
  } else {
    npp_harv_overtime <- harvest_cft_overtime + rharvest_cft_overtime +
Jannes Breier's avatar
Jannes Breier committed
      harvest_grasslands_overtime + harvest_bioenergy_overtime +
      timber_harvest_overtime + wood_harvest_overtime
Jannes Breier's avatar
Jannes Breier committed
  }
  biocol_overtime <- npp_harv_overtime + npp_luc_overtime
  biocol_overtime_frac_piref <- (
    biocol_overtime / mean(colSums(npp_ref * cellarea) / 10^15)
  )
  biocol_overtime_frac <- (
Jannes Breier's avatar
Jannes Breier committed
    biocol_overtime / npp_pot_overtime
Jannes Breier's avatar
Jannes Breier committed
  )
  biocol_luc <- npp_potential - npp
Jannes Breier's avatar
Jannes Breier committed

Jannes Breier's avatar
Jannes Breier committed
  # pick a PI window that excludes onset effects, but is reasonable early

  if (include_fire) {
    biocol_harvest <- (
      harvest_cft + rharvest_cft + harvest_grasslands + harvest_bioenergy +
Jannes Breier's avatar
Jannes Breier committed
        timber + fire + wood_harvest
Jannes Breier's avatar
Jannes Breier committed
    )
  } else {
    biocol_harvest <- (
      harvest_cft + rharvest_cft + harvest_grasslands + harvest_bioenergy +
Jannes Breier's avatar
Jannes Breier committed
        timber + wood_harvest
Jannes Breier's avatar
Jannes Breier committed
    )
  }
  biocol <- biocol_harvest + biocol_luc
  # set to 0 below lower threshold of NPP
  biocol[abs(npp_potential) < npp_threshold] <- 0
  # actual NPPpot as ref
  biocol_frac <- biocol / npp_potential
Jannes Breier's avatar
Jannes Breier committed

  # NPPpi as ref
  biocol_frac_piref <- biocol / rowMeans(npp_ref)
Jannes Breier's avatar
Jannes Breier committed

  # take the abs of biocol and sum that up for overtime
  biocol_overtime_abs <- colSums(abs(biocol * cellarea)) / 10^15
  biocol_overtime_abs_frac_piref <- biocol_overtime_abs * 10^15 /
Jannes Breier's avatar
Jannes Breier committed
    mean(colSums(npp_ref * cellarea))
  biocol_overtime_abs_frac <- biocol_overtime_abs / npp_pot_overtime
  # take the abs of biocol and sum that up for overtime
  biocol_pos <- biocol
  biocol_pos[biocol_pos < 0] <- 0
  biocol_overtime_pos <- colSums(biocol_pos * cellarea) / 10^15
  biocol_overtime_pos_frac_piref <- biocol_overtime_pos * 10^15 /
    mean(colSums(npp_ref * cellarea))
  biocol_overtime_pos_frac <- biocol_overtime_pos / npp_pot_overtime
Jannes Breier's avatar
Jannes Breier committed
  return(list(
    biocol_overtime = biocol_overtime,
    biocol_overtime_abs = biocol_overtime_abs,
    biocol_overtime_abs_frac_piref = biocol_overtime_abs_frac_piref,
    biocol_overtime_abs_frac = biocol_overtime_abs_frac,
    biocol_overtime_pos = biocol_overtime_pos,
    biocol_overtime_pos_frac_piref = biocol_overtime_pos_frac_piref,
    biocol_overtime_pos_frac = biocol_overtime_pos_frac,
Jannes Breier's avatar
Jannes Breier committed
    biocol_overtime_frac_piref = biocol_overtime_frac_piref,
    biocol_overtime_frac = biocol_overtime_frac,
    npp_harv_overtime = npp_harv_overtime,
    npp_luc_overtime = npp_luc_overtime,
    npp_act_overtime = npp_act_overtime,
    npp_pot_overtime = npp_pot_overtime,
    npp_eco_overtime = npp_eco_overtime,
    harvest_grasslands_overtime = harvest_grasslands_overtime,
    harvest_bioenergy_overtime = harvest_bioenergy_overtime,
    harvest_cft_overtime = harvest_cft_overtime,
    rharvest_cft_overtime = rharvest_cft_overtime,
    fire_overtime = fire_overtime,
    timber_harvest_overtime = timber_harvest_overtime,
    wood_harvest_overtime = wood_harvest_overtime,
    biocol = biocol,
    biocol_frac = biocol_frac,
    npp = npp,
    biocol_frac_piref = biocol_frac_piref,
    npp_potential = npp_potential,
    npp_ref = npp_ref,
    harvest_cft = harvest_cft,
    rharvest_cft = rharvest_cft,
    biocol_harvest = biocol_harvest,
    biocol_luc = biocol_luc,
    lat = lat,
    lon = lon,
    cellarea = cellarea
Jannes Breier's avatar
Jannes Breier committed
  )) # , biocol_luc_piref = biocol_luc_piref))
Jannes Breier's avatar
Jannes Breier committed
}

#' Calculate BioCol
#'
#' Wrapper function to calculate BioCol
#'
#' @param path_lu folder of landuse scenario run
#' @param path_pnv folder of pnv reference run
#' @param start_year first year of simulations
#' @param stop_year last year of simulations
#' @param reference_npp_time_span time span to read reference npp from, using
#'     index years 10:39 from potential npp input if set to NULL (default: NULL)
#' @param reference_npp_file file to read reference npp from, using
#'        potential npp input if set to NULL (default: NULL)
#' @param gridbased logical are pft outputs gridbased or pft-based?
#' @param read_saved_data flag whether to read previously saved data
#'        instead of reading it in from output files (default FALSE)
#' @param save_data whether to save input data to file (default FALSE)
#' @param data_file file to save/read input data to/from (default NULL)
#' @param include_fire boolean include firec in calculation of BioCol?
#'        (default TRUE)
#' @param external_fire instead of reading in firec for fire emissions, read in
#'        this external firec file from a separate spitfire run with disabled
#'        lighning. this will then include only human induced fires
#'        (default FALSE)
#' @param external_wood_harvest include external wood harvest from LUH2_v2h
#'        (default FALSE)
#' @param grass_scaling whether to scale pasture harvest according to
#'        data given via grass_harvest_file (default FALSE)
#' @param npp_threshold lower threshold for npp (to mask out non-lu areas
#'        according to Haberl et al. 2007). Below BioCol will be set to 0.
#'        (default: 20 gC/m2)
#' @param grass_harvest_file file containing grazing data to rescale the
#'        grassland harvests according to Herrero et al. 2013. File contains:
#'        grazing_data list object with $name and $id of 29 world regions, and
#'        $Herrero_2000_kgDM_by_region containing for each of these regions and
#'        mapping_lpj67420_to_grazing_regions array with a mapping between 67420
#'        LPJmL cells and the 29 regions
#' @param external_fire_file path to external file with human induced fire
#'        fraction c(cell,month,year) since 1500
#' @param external_wood_harvest_file path to R-file containing processed
#'        timeline of maps for LUH2_v2h woodharvest
#' @param replace_input_file_names list with alternative names for output
#'        identifiers to replace the ones in inst/ext_files/metric_files.yml.
#'        e.g. list(npp="mnpp") would replace the expected output for npp with
#'        mnpp followed by the automatically detected file extension (.bin.json)
#' @param suppress_warnings suppress warnings when reading files (default: TRUE)
Jannes Breier's avatar
Jannes Breier committed
#'
#' @return list data object containing BioCol and components as arrays: biocol,
#'         biocol_overtime, biocol_overtime_piref, biocol_frac, npp_potential,
#'         biocol_overtime_abs_frac_piref, biocol_frac_piref, npp_act_overtime,
#'         npp_pot_overtime, npp_eco_overtime, npp_ref, harvest_cft_overtime,
#'         npp_luc_overtime, rharvest_cft_overtime, fire_overtime,
#'         timber_harvest_overtime, harvest_cft, rharvest_cft,
#'         wood_harvest_overtime, biocol_harvest, biocol_luc, lat, lon, cellarea
Jannes Breier's avatar
Jannes Breier committed
#'
#' @examples
#' \dontrun{
#' calc_biocol(
#'   path_lu = run_folder,
#'   path_pnv = pnv_folder,
#'   gridbased = TRUE,
#'   start_year = 1980,
#'   stop_year = 2014,
#'   read_saved_data = FALSE,
#'   save_data = FALSE,
#'   npp_threshold = 20,
Jannes Breier's avatar
Jannes Breier committed
#' @export
calc_biocol <- function(
Jannes Breier's avatar
Jannes Breier committed
    path_lu,
    path_pnv,
    start_year,
    stop_year,
    reference_npp_time_span = NULL,
    reference_npp_file = NULL,
    gridbased = TRUE,
    read_saved_data = FALSE,
    save_data = FALSE,
    data_file = NULL,
    include_fire = FALSE,
    external_fire = FALSE,
    external_wood_harvest = FALSE,
    grass_scaling = FALSE,
    npp_threshold = 20,
Fabian Stenzel's avatar
Fabian Stenzel committed
    grass_harvest_file = NULL,
    external_fire_file = NULL,
    suppress_warnings = TRUE) {
  metric_files <- system.file(
    "extdata",
    "metric_files.yml",
    package = "biospheremetrics"
  ) %>%
    yaml::read_yaml()
Jannes Breier's avatar
Jannes Breier committed

  # translate output names (from metric_files.yml)
  # and folders to files_scenarios/reference lists
  file_extension <- get_major_file_ext(paste0(path_lu))
  files_scenario <- list()
  files_baseline <- list()
  for (output in names(metric_files$metric$biocol$output)) {
    # Iterate over all outputs
    if (is.null(replace_input_file_names[[output]])) {
      for (file in metric_files$file_name[[output]]) {
        full_file_path_lu <- paste0(path_lu, file, ".", file_extension)
        if (file.exists(full_file_path_lu)) {
          files_scenario[[output]] <- full_file_path_lu
        }
        full_file_path_pnv <- paste0(path_pnv, file, ".", file_extension)
        if (file.exists(full_file_path_pnv)) {
          files_baseline[[output]] <- full_file_path_pnv
        }
      }
      if (is.null(files_scenario[[output]])) {
        stop(
          "None of the default file names for ", output,
          " were found in ", path_lu, "please check or define manually",
          " using argument 'replace_input_file_names'. Stopping."
        )
        stop(
          "None of the default file names for ", output,
          " were found in ", path_pnv, "please check or define manually",
          " using argument 'replace_input_file_names'. Stopping."
        )
      files_scenario[[output]] <- paste0(
        path_lu,
        replace_input_file_names[[output]], ".", file_extension
      )
      files_baseline[[output]] <- paste0(
        path_pnv,
        replace_input_file_names[[output]], ".", file_extension
      )
Fabian Stenzel's avatar
Fabian Stenzel committed
  if (is.null(reference_npp_file)) reference_npp_file <- files_baseline$npp
Jannes Breier's avatar
Jannes Breier committed
    npp = reference_npp_file
Jannes Breier's avatar
Jannes Breier committed
  return(
    read_calc_biocol(
      files_scenario = files_scenario,
      files_baseline = files_baseline,
Jannes Breier's avatar
Jannes Breier committed
      files_reference = files_reference,
      time_span_scenario = as.character(start_year:stop_year),
      time_span_baseline = as.character(start_year:stop_year),
      time_span_reference = reference_npp_time_span,
Jannes Breier's avatar
Jannes Breier committed
      gridbased = gridbased,
      read_saved_data = read_saved_data,
      save_data = save_data,
      data_file = data_file,
      include_fire = include_fire,
      external_fire = external_fire,
      external_wood_harvest = external_wood_harvest,
      grass_scaling = grass_scaling,
      npp_threshold = npp_threshold,
      grass_harvest_file = grass_harvest_file,
      external_fire_file = external_fire_file,
      external_wood_harvest_file = external_wood_harvest_file,
      suppress_warnings = suppress_warnings
Jannes Breier's avatar
Jannes Breier committed
    )
  )