fireSense LCC flammability analysis

library(data.table)
library(ggplot2)
## reproducible is not needed by the fixture path; the commented live block
## below uses reproducible::prepInputs(), so load it if you run that.
library(sf)
library(terra)

Compare LCC and fire data

NRCan’s LCC2005_V1_4 product was retired (its ftp.ccrs.nrcan.gc.ca host no longer resolves), so this vignette uses the current Land Cover of Canada 2015 product hosted at ftp.maps.canada.ca. The same workflow applies to any LCC vintage. The build is cropped to a small study area (a 50 km square in central Saskatchewan) so the vignette completes in reasonable time; remove cropTo to analyse the full country.

## ---------------------------------------------------------------------------
## Inputs: pre-cropped fixtures shipped with the package (a 50 km square in
## central Saskatchewan). To run this against the live national datasets
## instead, use the commented block below.
## ---------------------------------------------------------------------------
lcc <- terra::rast(
  system.file("extdata", "lcc_studyArea.tif", package = "fireSenseUtils")
)
firePolygons <- sf::read_sf(
  system.file("extdata", "firePolygons_studyArea.gpkg", package = "fireSenseUtils")
)

## --- LIVE VERSION (not run) -------------------------------------------------
## Land Cover of Canada 2015 (1.9 GB zip) and the National Fire Database
## polygons (778 MB zip). Both are national-extent; `cropTo`/`st_crop` reduce
## them to the study area. Remove the crop to analyse the full country.
##
## lccUrl <- paste0(
##   "https://ftp.maps.canada.ca/pub/nrcan_rncan/Land-cover_Couverture-du-sol/",
##   "canada-landcover_canada-couverture-du-sol/CanadaLandcover2015.zip"
## )
## fireUrl <- paste0(
##   "https://cwfis.cfs.nrcan.gc.ca/downloads/nfdb/fire_poly/",
##   "current_version/NFDB_poly.zip"
## )
##
## dPath <- file.path(tempdir(), "fireSense_LCC_flammability")
## checkPath(dPath, create = TRUE)
##
## ## study area: 50 km square in central Saskatchewan
## studyArea <- vect(
##   cbind(c(-106, -105.5, -105.5, -106, -106),
##         c(54, 54, 54.5, 54.5, 54)),
##   type = "polygons", crs = "EPSG:4326"
## )
##
## lcc <- prepInputs(
##   url = lccUrl, destinationPath = dPath,
##   targetFile = "CAN_LC_2015_CAL.tif", alsoExtract = NA,
##   cropTo = studyArea, projectTo = NA, maskTo = NA,
##   fun = "terra::rast", overwrite = TRUE
## )
##
## firePolygons <- prepInputs(
##   url = fireUrl, destinationPath = dPath,
##   fun = "sf::read_sf", overwrite = TRUE
## )
## firePolygons <- sf::st_transform(firePolygons, crs = sf::st_crs(lcc))
## firePolygons <- sf::st_crop(firePolygons, sf::st_bbox(lcc))
## firePolygons <- firePolygons[firePolygons$YEAR > 2004, ]
##
## NOTE: NFDB_poly.zip contains TWO layers -- 1972to2020 and 2021to2024.
## `sf::read_sf` reads only the first, so the live version above silently
## excludes fires after 2020. The fixture combines both, then filters
## YEAR > 2004, and therefore covers 2007-2024.
##
## GDAL can also read these archives without downloading them, via
## `/vsizip//vsicurl/<url>`, which fetches only the byte ranges needed. That
## is how the fixtures here were built.
## ---------------------------------------------------------------------------

firePolygons$dummyVar <- 1L

## rasterize burned area onto the LCC grid, then collapse to one row per LCC class
fireRaster <- terra::rasterize(terra::vect(firePolygons), lcc, field = "dummyVar")
burned <- data.table(
  pixelID = seq_len(terra::ncell(lcc)),
  lcc     = terra::values(lcc, mat = FALSE),
  burn    = terra::values(fireRaster, mat = FALSE)
)
burnCalc <- burned[, .(available = .N,
                       burned    = sum(burn, na.rm = TRUE)), by = lcc]
burnCalc[, percentBurned := round(burned / available * 100, digits = 3)]
setkey(burnCalc, lcc)
burnCalc
#> Key: <lcc>
#>       lcc available burned percentBurned
#>     <int>     <int>  <int>         <num>
#>  1:     1    731278   4717         0.645
#>  2:     2        10      0         0.000
#>  3:     5    249894    411         0.164
#>  4:     6    224693   1420         0.632
#>  5:     8    301291 156689        52.006
#>  6:    10     87696  72885        83.111
#>  7:    14    492761    575         0.117
#>  8:    16      1294    256        19.784
#>  9:    17     10856     95         0.875
#> 10:    18    586970   1416         0.241

Plot

From the plot above (and based on descriptions of each class) we determine the following non-flammable classes:

## original fireSense_dataPrepFit defaults
LCC2005_nonFlam <- c(0, 25, 30, 33, 36, 37, 38, 39)

And for fireSense categories:

  • non-forest high-flammability:
  • non-forest low-flammability: