-
David Minor authoreda709bcb3
biomass_support.R 11.29 KiB
mosaic_list <- function(x, fun, datatype, format, options, overwrite,
tolerance=0.05, filename="") {
mosaic_args <- x
if (!missing(fun)) mosaic_args$fun <- fun
if (!missing(tolerance)) mosaic_args$tolerance <- tolerance
if (!missing(datatype)) mosaic_args$datatype <- datatype
if (!missing(format)) mosaic_args$format <- format
if (!missing(options)) mosaic_args$options <- options
if (!missing(overwrite)) mosaic_args$overwrite <- overwrite
mosaic_args$filename <- filename
do.call(mosaic, mosaic_args)
}
# Read in CCI biomass within a given area of interest. Multiple years can be provided as a vector
# Combines AGBD and SD into as layers in one raster mosaic
readCCI <- function(data_folder, year="2020", version=3, aoi, verbose=FALSE){
# 2010, 2017, 2018 available for CCI Biomass v2.0
# 2020 available for CCI Biomass v3.0
year <- as.character(year)
if(version ==2){
#v2.0 file format
file_root <- paste0('_ESACCI-BIOMASS-L4-AGB-MERGED-100m-', year, '-fv2.0.tif')
file_root_sd <- paste0('_ESACCI-BIOMASS-L4-AGB_SD-MERGED-100m-', year, '-fv2.0.tif')
}
if(version==3){
#v3.0 file format
file_root <- paste0('_ESACCI-BIOMASS-L4-AGB-MERGED-100m-', year, '-fv3.0.tif')
file_root_sd <- paste0('_ESACCI-BIOMASS-L4-AGB_SD-MERGED-100m-', year, '-fv3.0.tif')
}
filename=""
tile_stacks <- c()
for (n in 1:length(tiles)) {
#for (n in c(4,5,7,8)) { #Temporary restriction to tiles while bugs are worked out with rasters
#for (n in 2) { #Temporary restriction to tiles while bugs are worked out with rasters
tile <- tiles[n]
min_x <- bbox(tile)[1, 1]
max_y <- bbox(tile)[2, 2]
if (min_x < 0) {
min_x <- paste0('W', sprintf('%03i', abs(min_x)))
} else {
min_x <- paste0('E', sprintf('%03i', min_x))
}
if (max_y < 0) {
max_y <- paste0('S', sprintf('%02i', abs(max_y)))
} else {
max_y <- paste0('N', sprintf('%02i', max_y))
}
file_prefix <- paste0(max_y, min_x)
band_names2 <- c(paste0('agbd_', year), paste0('agbd_sd_', year))
filenames2 <- c(file.path(data_folder, year, paste0(file_prefix, file_root)), file.path(data_folder, year, paste0(file_prefix, file_root_sd)))
if(verbose){
print(filenames2)
}
if (!file.exists(filenames2[1])){
print(paste0(filenames2, " does not exist"))
next()
}
tile_stack <- crop(stack(filenames2), aoi, datatype="INT1U", format='GTiff', options="COMPRESS=LZW")
names(tile_stack) <- band_names2
tile_stacks <- c(tile_stacks, list(tile_stack))
}
#If there are multiple tiles, create mosaic. Otherwise mosaic only includes 1 tile
if (length(tile_stacks) > 1) {
tile_mosaic <- mosaic_list(tile_stacks, fun='mean', filename=filename,
datatype='INT1U', format='GTiff',
options='COMPRESS=LZW')
} else {
tile_mosaic <- tile_stacks[[1]]
if (filename != '') {
tile_mosaic <- writeRaster(tile_mosaic, filename=filename,
datatype="INT1U", format="GTiff",
options="COMPRESS=LZW")
}
}
names(tile_mosaic) <- band_names2
NAvalue(tile_mosaic) <- -1
cci <- tile_mosaic
return(cci)
}
readGFC <- function(data_folder, image=c('treecover2000', 'treecover2020', 'lossyear', 'gain'), aoi, verbose=FALSE){
dataset <- 'GFC-2020-v1.8'
file_root <- paste0('Hansen_', dataset, '_')
filename=""
tile_stacks <- c()
for (n in 1:length(tiles)) {
#for (n in 2) {
tile <- tiles[n]
min_x <- bbox(tile)[1, 1]
max_y <- bbox(tile)[2, 2]
if (min_x < 0) {
min_x <- paste0(sprintf('%03i', abs(min_x)), 'W')
} else {
min_x <- paste0(sprintf('%03i', min_x), 'E')
}
if (max_y < 0) {
max_y <- paste0(sprintf('%02i', abs(max_y)), 'S')
} else {
max_y <- paste0(sprintf('%02i', max_y), 'N')
}
file_suffix <- paste0('_', max_y, '_', min_x, '.tif')
image_names2 <- image
band_names2 <- image_names2
filenames2 <- file.path(data_folder, paste0(file_root, image_names2, file_suffix))
if(verbose){
print(filenames2)
}
if (!file.exists(filenames2[1])){
print(paste0(filenames2, " does not exist"))
next()
}
#tile_stack <- try(crop(stack(filenames2), aoi, datatype='INT1U', format='GTiff', options="COMPRESS=LZW"))
tile_stack <- crop(stack(filenames2), aoi, datatype='INT1U', format='GTiff', options="COMPRESS=LZW")
names(tile_stack) <- band_names2
tile_stacks <- c(tile_stacks, list(tile_stack))
}
if (length(tile_stacks) > 1) {
tile_mosaic <- mosaic_list(tile_stacks, fun='mean', filename=filename,
datatype='INT1U', format='GTiff',
options='COMPRESS=LZW')
} else {
tile_mosaic <- tile_stacks[[1]]
if (filename != '') {
tile_mosaic <- writeRaster(tile_mosaic, filename=filename,
datatype="INT1U", format="GTiff",
options="COMPRESS=LZW")
}
}
names(tile_mosaic) <- band_names2
NAvalue(tile_mosaic) <- -1
gfc <- tile_mosaic
return(gfc)
}
recode_gfc <- function(treecover2000, treecover2020, lossyear, gain) {
forest_threshold <- 30
forest2000 <- treecover2000 > forest_threshold
forest2020 <- treecover2020 > forest_threshold
# Note forest2000 is a binary variable
lossyear_recode <- lossyear * forest2000
gain_recode <- gain & (!forest2000)
lossgain <- gain & (lossyear != 0)
thresholded <- matrix(c(forest2000, forest2020, lossyear_recode, gain_recode, lossgain),
nrow=length(forest2000),
ncol=5)
return(thresholded)
}
recode_gfc2020 <- function(treecover2020) {
forest_threshold <- 30
forest2020 <- treecover2020 > forest_threshold
thresholded <- matrix(c(forest2020),
nrow=length(forest2020),
ncol=1)
return(thresholded)
}
agbd_table <- function(year=2020, agb_thresholded, agb_masked){
scale_factor=0.0001
agb_boundpoly <- as(extent(agb_thresholded), 'SpatialPolygons')
proj4string(agb_boundpoly) <- proj4string(agb_thresholded)
agb_boundpoly_wgs84 <- spTransform(agb_boundpoly, CRS('+init=epsg:4326'))
aoi_wgs84 <- spTransform(aoi, CRS('+init=epsg:4326'))
if (!gIntersects(agb_boundpoly_wgs84, aoi_wgs84)) {
stop('aoi does not intersect supplied Biomass extract')
}
if ((((xmin(agb_thresholded) >=-180) & (xmax(agb_thresholded) <=180)) || ((xmin(agb_thresholded) >=0) & (xmax(agb_thresholded) <=360))) &&
(ymin(agb_thresholded) >=-90) & (ymax(agb_thresholded) <= 90)) {
# Use the included calc_pixel_area function to calculate the area of
# one cell in each line of the raster, allowing for accurate areal
# estimates in square meters even when imagery is in
# WGS84.
message('Data appears to be in latitude/longitude. Calculating cell areas on a sphere.')
spherical_areas <- TRUE
# Calculate the area of a single pixel in each line of the image (to
# avoid repeating this calculation later on)
x <- cci
xleft <- xmin(x)
xright <- xmin(x) + xres(x)
ylower <- seq(from=(ymax(x) - yres(x)), by=(-yres(x)), length.out=nrow(x))
yupper <- seq(from=ymax(x), by=(-yres(x)), length.out=nrow(x))
poly_areas <- function(xl, xr, yl, yu) {
areaPolygon(matrix(c(xl, yl,
xr, yl,
xr, yu,
xl, yu), ncol=2, byrow=TRUE))
}
pixel_areas <- mapply(poly_areas, xleft, xright, ylower, yupper)
} else {
spherical_areas <- FALSE
pixel_areas <- xres(agb_thresholded) * yres(agb_thresholded)
}
aoi <- spTransform(aoi, CRS(proj4string(agb_thresholded)))
if (!('label' %in% names(aoi))) {
aoi$label <- paste('AOI', seq(1:nrow(aoi@data)))
}
uniq_aoi_labels <- unique(aoi$label)
years <- as.numeric(year)
agb_table <- data.frame(year=rep(years, length(uniq_aoi_labels)),
aoi=rep(uniq_aoi_labels, each=length(years)))
agb_table$agb <- 0
agb_table$agbd <- 0
agb_table$area <- 0
agb_table$n_pixel <- 0
#agb_table$agbd_sd <- 0
n_years <- length(years)
for (n in 1:nrow(aoi)) {
#cci_masked <- mask(cci_thresholded, aoi[n, ], datatype='INT1U', format="GTiff",
# options="COMPRESS=LZW")
# Find the first row in the loss table that applies to this aoi
agb_table_st_row <- match(aoi[n, ]$label, agb_table$aoi)
# No loss in first year
#agb_table$agb[loss_table_st_row] <- NA
# Process by blocks to avoid unnecessary reads from disk
bs <- blockSize(agb_masked)
for (block_num in 1:bs$n) {
bl_st_row <- bs$row[block_num]
bl_nrows <- bs$nrows[block_num]
agb_bl <- getValuesBlock(agb_masked, bl_st_row, bl_nrows)
if (spherical_areas) {
bl_pixel_areas <- rep(pixel_areas[bl_st_row:(bl_st_row + bl_nrows - 1)], each=ncol(agb_thresholded))
} else {
bl_pixel_areas <- pixel_areas
}
# Calculate initial aboveground biomass, note that areas are converted to square
# meters using pixel size, then converted using scale_factor
# (default output units are Mg)
# agbinit_col <- grep(paste0('agb_',year[1]), names(cci))
# agb_table$agb[agb_table_st_row] <- agb_table$agb[agb_table_st_row] +
# sum(cci_bl[, agbinit_col] * bl_pixel_areas * scale_factor, na.rm=TRUE)
# agb_table$agbd[agb_table_st_row + i] <- agb_table$agbd[agb_table_st_row + i] +
# mean((cci_bl[, agb_col] == i), na.rm=TRUE)
for (i in 0:(n_years-1)) {
#agbd_col <- grep(paste0('agbd_',year[i+1]), names(cci_thresholded))
#sd_col <- grep(paste0('agbd_sd_',year[i+1]), names(cci_thresholded))
# n + 1 because first row is year 2010
agb_table$agb[agb_table_st_row + i] <- agb_table$agb[agb_table_st_row + i] +
sum(agb_bl * bl_pixel_areas * scale_factor, na.rm=TRUE)
agb_table$area[agb_table_st_row + i] <- agb_table$area[agb_table_st_row + i] +
sum((!is.na(agb_bl))*bl_pixel_areas * scale_factor, na.rm=TRUE)
agb_table$n_pixel[agb_table_st_row + i] <- agb_table$n_pixel[agb_table_st_row + i] +
sum(!is.na(agb_bl))
if(bl_st_row==1){
agb_table$agbd[agb_table_st_row + i] <- mean(agb_bl, na.rm=TRUE)
# agb_table$agbd_sd[agb_table_st_row + i] <- mean(cci_bl[, sd_col], na.rm=TRUE)
} else{
agb_table$agbd[agb_table_st_row + i] <- weighted.mean(c(agb_table$agbd[agb_table_st_row + i],
mean(agb_bl, na.rm=TRUE)), w=c((bl_st_row-1), bl_nrows), na.rm=TRUE)
# agb_table$agbd_sd[agb_table_st_row + i] <- weighted.mean(c(agb_table$agbd_sd[agb_table_st_row + i],
# mean(cci_bl[, sd_col], na.rm=TRUE)), w=c((bl_st_row-1), bl_nrows), na.rm=TRUE)
}
}
}
}
return(agb_table)
}