| Title: | Utilities for Working With the 'fireSense' Group of 'SpaDES' Modules |
|---|---|
| Description: | Utilities for working with the 'fireSense' group of 'SpaDES' modules. |
| Authors: | Jean Marchal [aut], Eliot J B McIntire [aut, cre] (ORCID: <https://orcid.org/0000-0002-6914-8316>), Alex M Chubaty [aut] (ORCID: <https://orcid.org/0000-0001-7146-8135>), Ian Eddy [aut] (ORCID: <https://orcid.org/0000-0001-7397-2116>) |
| Maintainer: | Eliot J B McIntire <[email protected]> |
| License: | GPL-3 |
| Version: | 0.2.3.9098 |
| Built: | 2026-10-16 01:42:33 UTC |
| Source: | https://github.com/PredictiveEcology/fireSenseUtils |
fireSenseUtils packageUtilities for working with the 'fireSense' group of 'SpaDES' modules.
Maintainer: Eliot J B McIntire [email protected] (ORCID)
Authors:
Eliot J B McIntire [email protected] (ORCID)
Jean Marchal [email protected]
Alex M Chubaty [email protected] (ORCID)
Ian Eddy [email protected] (ORCID)
Useful links:
Report bugs at https://github.com/PredictiveEcology/fireSenseUtils/issues
fireSense_spreadFit moduleObjective function for fireSense_spreadFit module
.objfunSpreadFit( par, landscape, annualDTx1000, nonAnnualDTx1000, formulaToFit, historicalFires, fireBufferedListDT, covMinMax = NULL, maxFireSpread = spreadProbCeiling, lowerSpreadProb = spreadProbFloor, minFireSize = 2, escapeSizeHa = NULL, jumpTries = 0, jumpMeanDist = 0, yearAreaWeight = 0, areaDistWeight = 0, returnTerms = FALSE, tests = "snll_fs", Nreps = 10, mutuallyExclusive = list(youngAge = c("class", "nf")), doAssertions = TRUE, plot.it = FALSE, objFunCoresInternal = 1, lanscape1stQuantileThresh = 0.265, thresh = 550, pruneAbove = Inf, covCentre = NULL, weighted = TRUE, sizeLik = "kde", sizeLikDf = 5, adWeight = "auto", link = NULL, returnSims = FALSE, returnBurned = FALSE, penaliseRunaways = TRUE, runawayEdgeFrac = fireSenseRunawayEdgeFrac, runawayEdgeMin = fireSenseRunawayEdgeMin, runawaySize = NULL, runawayBufferMultiple = NULL, fitYearSpreadSD = NULL, verbose = 2, ... ).objfunSpreadFit( par, landscape, annualDTx1000, nonAnnualDTx1000, formulaToFit, historicalFires, fireBufferedListDT, covMinMax = NULL, maxFireSpread = spreadProbCeiling, lowerSpreadProb = spreadProbFloor, minFireSize = 2, escapeSizeHa = NULL, jumpTries = 0, jumpMeanDist = 0, yearAreaWeight = 0, areaDistWeight = 0, returnTerms = FALSE, tests = "snll_fs", Nreps = 10, mutuallyExclusive = list(youngAge = c("class", "nf")), doAssertions = TRUE, plot.it = FALSE, objFunCoresInternal = 1, lanscape1stQuantileThresh = 0.265, thresh = 550, pruneAbove = Inf, covCentre = NULL, weighted = TRUE, sizeLik = "kde", sizeLikDf = 5, adWeight = "auto", link = NULL, returnSims = FALSE, returnBurned = FALSE, penaliseRunaways = TRUE, runawayEdgeFrac = fireSenseRunawayEdgeFrac, runawayEdgeMin = fireSenseRunawayEdgeMin, runawaySize = NULL, runawayBufferMultiple = NULL, fitYearSpreadSD = NULL, verbose = 2, ... )
par |
parameters: the logistic parameters ( |
landscape |
A |
annualDTx1000 |
A list of data.table class objects. Each list element is
data from a single calendar year, and whose name takes the form |
nonAnnualDTx1000 |
Like |
formulaToFit |
Formula, put provided as a character string, not class |
historicalFires |
A named list of |
fireBufferedListDT |
A named list of |
covMinMax |
This is a 2 row by multiple column data.frame indicating the minimum and maximum values of the original covariate data values. These will be used to rescale the covariates internally so that they are all between 0 and 1. It is important to not simply rescale internally here because only 1 year is run at a time; all years must be rescaled for a given covariate by the same amount. |
maxFireSpread |
A value for |
lowerSpreadProb |
Numeric. Lower bound for |
minFireSize |
Integer. Minimum fire size (in pixels) to include when
scoring simulated against historical fires; fires smaller than this are
filtered out of the comparison. Default |
escapeSizeHa |
Numeric or |
jumpTries, jumpMeanDist
|
Used with |
yearAreaWeight |
Weight of the annual-area term: each fit year's observed area burned scored against
that year's simulated totals, one per replicate, with the per-fire size likelihood ( |
areaDistWeight |
Weight of the area-weighted size-distribution term ( |
returnTerms |
Logical. |
tests |
One or more of |
Nreps |
Integer. The number of replicates, per ignition, to run. |
mutuallyExclusive |
Named list of vectors describing groups of model
terms that must not be active together (mutually exclusive in the
formula). Default |
doAssertions |
Logical. If |
plot.it |
Passed to |
objFunCoresInternal |
Internally, this function can use |
lanscape1stQuantileThresh |
A |
thresh |
Threshold multiplier used in SNLL fire size ( |
pruneAbove |
Numeric. An upper bound on the accumulated SNLL after the first batch of
fire years, past which the evaluation stops early and returns the fail value. Default A caller that runs one DEoptim generation per call knows the current population, and can pass
the worst objective value that population would accept. Doing so is exact, not a heuristic:
the second batch contributes a non-negative SNLL, so the first batch's accumulated value is a
lower bound on the evaluation's final value. A trial exceeding |
covCentre |
Optional named list or vector of values subtracted from the rescaled covariates
of the same name. |
weighted |
Should each fire's log-likelihood be multiplied by a weight that grows with its
observed size, to give large fires more influence on the SNLL? |
sizeLik |
How a fire's likelihood is taken from its |
sizeLikDf |
Degrees of freedom of the Student-t when |
adWeight |
What the |
link |
Passed to |
returnSims |
If |
returnBurned |
If |
penaliseRunaways |
If |
runawayEdgeFrac, runawayEdgeMin
|
A replicate is a runaway only if it burns at least |
runawaySize |
|
runawayBufferMultiple |
|
fitYearSpreadSD |
If |
verbose |
If >= 2, then this will show more information about |
... |
This is not used here, but allows for extraneous arguments to not break this function.
The removed arguments |
Attempting a weighted likelihood,
https://stats.stackexchange.com/questions/267464/algorithms-for-weighted-maximum-likelihood-parameter-estimation.
With log(fireSize) * likelihood for each fire.
Abbreviate species names for fuel classes
abbreviateSpNames(df)abbreviateSpNames(df)
df |
data.table |
data.table
The multiplier that gives the "adTest" term and the fire-size SNLL about equal influence on the
objective, c * sqrt(nFires). Both terms are sums over the fitted fires, so both grow with how
many there are; measured across six ELFs (138 to 1624 fires, 2,708 to 1,114,569 pixels burned,
14 members of each fit's final population), the spread of the SNLL across members grew with
nFires^0.5 to nFires^1, and neither term scaled with the ELF's area or its area burned. c
comes from the same measurements, one per sizeLik and weighted combination. Under it the AD
term's share of the influence stayed within 0.36-0.68 of the total, against 0.16-0.94 under the
fixed 50.
adWeightAuto(nFires, sizeLik = "kde", weighted = FALSE)adWeightAuto(nFires, sizeLik = "kde", weighted = FALSE)
nFires |
Number of fires being fitted (after |
sizeLik |
As in |
weighted |
As in |
The constants were measured on populations fitted with an older objective, and a spread estimated from 14 members is coarse, so treat the result as the right order of magnitude rather than exact.
A single numeric.
SpatRaster to data.table
Convert list of annual SpatRaster to data.table
annualStackToDTx1000(x, whNotNA, ...) ## S3 method for class 'SpatRaster' annualStackToDTx1000(x, whNotNA, ...) ## S3 method for class 'Raster' annualStackToDTx1000(x, whNotNA, ...) ## S3 method for class 'list' annualStackToDTx1000(x, whNotNA, ...)annualStackToDTx1000(x, whNotNA, ...) ## S3 method for class 'SpatRaster' annualStackToDTx1000(x, whNotNA, ...) ## S3 method for class 'Raster' annualStackToDTx1000(x, whNotNA, ...) ## S3 method for class 'list' annualStackToDTx1000(x, whNotNA, ...)
x |
|
whNotNA |
Pixel indexes that should go through this process (i.e. not NA) |
... |
Not currently used |
data.table of the SpatRaster or the list
withr::local_package("raster") r1 <- raster(extent(0, 10, 0, 10), vals = 1:100) r2 <- raster(extent(0, 10, 0, 10), vals = 100:1) r3 <- raster(extent(0, 10, 0, 10), vals = 200:101) r4 <- raster(extent(0, 10, 0, 10), vals = 300:201) # list of Rasters lRast <- list(r1, r2, r3) lRast[[1]][5] <- NA whNotNA <- setdiff(1:ncell(r1), 5) # unnamed -- should error try(out1 <- annualStackToDTx1000(lRast, whNotNA)) # named names(lRast) <- c("OneToHun", "HunToOne", "TwoHunToOneHun") out1 <- annualStackToDTx1000(lRast, whNotNA) # RasterStack out2 <- annualStackToDTx1000(raster::stack(lRast), whNotNA) # List of RasterStacks s1 <- raster::stack(r1, r2) names(s1) <- names(lRast)[1:2] s2 <- raster::stack(r4, r3) names(s2) <- c(names(lRast)[3], "ThreeHunToTwoHun") out3 <- annualStackToDTx1000(list(s1 = s1, s2 = s2), whNotNA) ## named list required # With duplicated names -- to remove duplicates; # actually, this doesn't make sense: RasterStack can't have duplicated names names(lRast) <- c("OneToHun", "OneToHun", "TwoHunToOneHun") out4 <- annualStackToDTx1000(raster::stack(lRast), whNotNA) ## cleanup withr::deferred_run()withr::local_package("raster") r1 <- raster(extent(0, 10, 0, 10), vals = 1:100) r2 <- raster(extent(0, 10, 0, 10), vals = 100:1) r3 <- raster(extent(0, 10, 0, 10), vals = 200:101) r4 <- raster(extent(0, 10, 0, 10), vals = 300:201) # list of Rasters lRast <- list(r1, r2, r3) lRast[[1]][5] <- NA whNotNA <- setdiff(1:ncell(r1), 5) # unnamed -- should error try(out1 <- annualStackToDTx1000(lRast, whNotNA)) # named names(lRast) <- c("OneToHun", "HunToOne", "TwoHunToOneHun") out1 <- annualStackToDTx1000(lRast, whNotNA) # RasterStack out2 <- annualStackToDTx1000(raster::stack(lRast), whNotNA) # List of RasterStacks s1 <- raster::stack(r1, r2) names(s1) <- names(lRast)[1:2] s2 <- raster::stack(r4, r3) names(s2) <- c(names(lRast)[3], "ThreeHunToTwoHun") out3 <- annualStackToDTx1000(list(s1 = s1, s2 = s2), whNotNA) ## named list required # With duplicated names -- to remove duplicates; # actually, this doesn't make sense: RasterStack can't have duplicated names names(lRast) <- c("OneToHun", "OneToHun", "TwoHunToOneHun") out4 <- annualStackToDTx1000(raster::stack(lRast), whNotNA) ## cleanup withr::deferred_run()
Covariates were historically required to lie in [0, 1]. That upper bound was a
convention of the log-biomass parameterisation, not a requirement of the objective
function: covariates enter only through exp(mat %*% covPars) inside logistic3p(),
which saturates gracefully (exp(Inf)^(-b) is 0, giving maxAsymptote) and never
produces NaN. Fuel covariates expressed as biomass / 1e4 legitimately exceed 1,
so only non-negativity and finiteness are enforced.
assertCovariateRange(dt, colsToUse)assertCovariateRange(dt, colsToUse)
dt |
A |
colsToUse |
Character vector of covariate column names to check. |
invisible(TRUE), or an error.
Semi-automated selection of fuel classed based on GLMs
assessFuelClasses( landscape, fuelCol, sppEquiv, sppEquivCol, targetNonForestClasses = 2, targetFuelClasses = 5, nonforestLCC, pValue = 0.001, lccShare = NULL, minCovariateProp = 0.05 )assessFuelClasses( landscape, fuelCol, sppEquiv, sppEquivCol, targetNonForestClasses = 2, targetFuelClasses = 5, nonforestLCC, pValue = 0.001, lccShare = NULL, minCovariateProp = 0.05 )
landscape |
data.table created by |
fuelCol |
the column in |
sppEquiv |
table with species name equivalencies between the kNN and final naming formats.
See |
sppEquivCol |
the column name to use from |
targetNonForestClasses |
the number of non-forest fuel classes to generate |
targetFuelClasses |
target number of treed fuel classes to generate |
nonforestLCC |
vector or list of vectors of non-forest fuel classes |
pValue |
for glm coefficient significance when deciding to merge fuel classes |
lccShare |
Optional named numeric: each land-cover class's share of the ELF's flammable
pixels, named by class code (see |
minCovariateProp |
With |
a list of three objects:
modSppEquiv, a data.table with assigned fuel classes for each tree species;
nonForestedLCCGroups, a named list of non-forest land cover classes grouped by fuel class;
missingLCCgroup, the class in nonForestLCCGroups to assign forested pixels missing from cohortData;
A simulated fire that reaches the outer edge of its own buffer has run away: the spread
objective (.objfunSpreadFit()) censors it. bufferEdge() marks the pixels that make that
edge: a pixel of a fire's buffer (burned or not) with at least one of its eight (queen)
neighbours outside that fire's own buffer. "Outside" is anything that is not a row of the same
fire in the table: unburned land of another fire's buffer, pixels removed as non-flammable (see
removeBufferedFiresOutsideRTM()), NA cells, and the raster's boundary.
bufferEdge(fireBufferedDT, r) addBufferEdge(fireBufferedListDT, landscape)bufferEdge(fireBufferedDT, r) addBufferEdge(fireBufferedListDT, landscape)
fireBufferedDT |
A table of one fire year with columns |
r |
A raster with the grid |
fireBufferedListDT |
A list of tables as |
landscape |
As |
bufferEdge(): a logical vector, one element per row of fireBufferedDT.
addBufferEdge(): fireBufferedListDT with that vector as a column edge in every table
that does not have one already (the tables are copied, not modified).
Create buffers around polygons based on area target for buffer
bufferToArea( poly, rasterToMatch, areaMultiplier, verb = FALSE, polyName = NULL, field = NULL, minSize = 500, cores = 1, ... ) ## S3 method for class 'list' bufferToArea( poly, rasterToMatch, areaMultiplier = 10, verb = FALSE, polyName = NULL, field = NULL, minSize = 500, cores = 1, ... ) ## S3 method for class 'SpatialPolygons' bufferToArea( poly, rasterToMatch, areaMultiplier = 10, verb = FALSE, polyName = NULL, field = NULL, minSize = 500, cores = 1, ... ) ## S3 method for class 'sf' bufferToArea( poly, rasterToMatch, areaMultiplier = 10, verb = FALSE, polyName = NULL, field = NULL, minSize = 500, cores = 1, ... )bufferToArea( poly, rasterToMatch, areaMultiplier, verb = FALSE, polyName = NULL, field = NULL, minSize = 500, cores = 1, ... ) ## S3 method for class 'list' bufferToArea( poly, rasterToMatch, areaMultiplier = 10, verb = FALSE, polyName = NULL, field = NULL, minSize = 500, cores = 1, ... ) ## S3 method for class 'SpatialPolygons' bufferToArea( poly, rasterToMatch, areaMultiplier = 10, verb = FALSE, polyName = NULL, field = NULL, minSize = 500, cores = 1, ... ) ## S3 method for class 'sf' bufferToArea( poly, rasterToMatch, areaMultiplier = 10, verb = FALSE, polyName = NULL, field = NULL, minSize = 500, cores = 1, ... )
poly |
|
rasterToMatch |
A |
areaMultiplier |
Either a scalar that will buffer |
verb |
Logical or numeric related to how much verbosity is printed. |
polyName |
Optional character string of the polygon layer name (not the individual polygons
on a |
field |
Passed to |
minSize |
The absolute minimum size of the buffer & non-buffer together. This will
be imposed after |
cores |
number of processor cores to use |
... |
passed to |
A data.table (or list of data.tables if poly was a list) with 2 columns:
buffer and pixelID. buffer is either 1 (the original polygon) or
0 (in the buffer).
Create a variable sized buffer around a set of pixels belonging to the same fire ID
bufferToAreaRast(fireIDraster, areaMultiplier, minSize, flammableRTM, verb = 1)bufferToAreaRast(fireIDraster, areaMultiplier, minSize, flammableRTM, verb = 1)
fireIDraster |
a |
areaMultiplier |
A scalar that will buffer |
minSize |
The absolute minimum size of the buffer & non-buffer together.
This will be imposed after |
flammableRTM |
a |
verb |
Logical or numeric related to how much verbosity is printed. |
a data.table with fire ID, buffer status, and pixelID
cohortData with burn columnModify cohortData with burn column
buildCohortBurnHistory(cohortData, pixelGroupMap, firePolys, year)buildCohortBurnHistory(cohortData, pixelGroupMap, firePolys, year)
cohortData |
either a |
pixelGroupMap |
either a |
firePolys |
the output of |
year |
length-two vector giving temporal period used to subset |
cohortData modified with burn status
youngAge maskIdentifies pixels that have any non-forest presence (based on the
non-pixelID columns of landcoverDT) and whose age is below
cutoffForYoungAge. It then sets those pixels to 0 across all layers of
LCCras and appends a new single-layer raster named youngAge with 1 for
the affected pixels and 0 elsewhere (preserving NA where present in the
template).
calcNonForestYoungAge(landcoverDT, NFTSD, LCCras, cutoffForYoungAge)calcNonForestYoungAge(landcoverDT, NFTSD, LCCras, cutoffForYoungAge)
landcoverDT |
data.table.
A |
NFTSD |
numeric.
A numeric vector (or similar) that can be indexed by |
LCCras |
SpatRaster.
A |
cutoffForYoungAge |
numeric(1).
Age threshold; pixels with |
The function proceeds as follows:
Determines the set of non-forest columns as all columns in landcoverDT
except pixelID, and computes a per-row sum (sumRows).
Retrieves pixel ages from NFTSD using pixelID as indices.
Selects pixels where sumRows > 0 and age <= cutoffForYoungAge;
these pixels are considered "young non-forest".
Sets those pixels to 0 in every layer of LCCras using cell indexing.
Builds a new single-layer raster with 1 at those pixel locations and 0
elsewhere (respecting NA from the template), and adds it to LCCras
as a layer named youngAge.
Assumptions / requirements
LCCras is a terra::SpatRaster (possibly multi-layer). Cell indexing
with LCCras[pixToChange] <- 0 applies across all layers for the indexed
cells.
landcoverDT is a data.table with:
a pixelID column of integer cell indices (1-based) consistent with
LCCras cell numbering, and
all other columns representing non-forest variables whose row-wise sum
indicates presence (sumRows > 0).
NFTSD is a numeric vector (or similar) indexable by pixelID, providing
the age (in the same units as cutoffForYoungAge) for each cell.
cutoffForYoungAge is a scalar numeric threshold; pixels with age <= cutoffForYoungAge are flagged as "young".
Notes
The function modifies LCCras in place (by reference to the object passed
in) and returns the modified raster with an extra youngAge layer.
NA cells in LCCras remain NA in the created youngAge layer.
The landcoverDT temporary columns sumRows and age are removed prior
to return.
A terra::SpatRaster identical to LCCras but with:
all "young non-forest" pixels set to 0 across its existing layers, and
an additional layer named youngAge where flagged pixels are 1, others are
0, and NAs follow the template mask.
Terra package reference manual and vignettes for SpatRaster operations
(Hijmans, R.J.).
data.table reference: .SD, :=, and efficient grouping/filtering
(Dowle, M., & Srinivasan, A.).
terra::rast(), terra::values(), terra::setValues() for raster creation
and manipulation.
data.table semantics for .SD, in-place updates (:=), and fast
row/column operations.
## Not run: library(terra) library(data.table) # Build a small template raster r <- rast(nrows = 3, ncols = 3) values(r) <- c(NA, 0, 0, 0, 0, NA, 0, 0, 0) # Make a 2-layer LCC raster (copy template twice) LCC <- c(r, r) names(LCC) <- c("LCC1", "LCC2") # A data.table with pixel indices and two non-forest columns dt <- data.table( pixelID = c(2, 3, 4, 5, 7, 8, 9), NF1 = c(1, 0, 0, 2, 0, 0, 1), NF2 = c(0, 1, 0, 0, 0, 3, 0) ) # Age vector indexed by cell ID (length ncell(LCC)) ages <- seq_len(ncell(LCC)) * 5 # toy ages out <- calcNonForestYoungAge( landcoverDT = dt, NFTSD = ages, LCCras = LCC, cutoffForYoungAge = 15 ) out names(out) # "LCC1" "LCC2" "youngAge" plot(out$youngAge) ## End(Not run)## Not run: library(terra) library(data.table) # Build a small template raster r <- rast(nrows = 3, ncols = 3) values(r) <- c(NA, 0, 0, 0, 0, NA, 0, 0, 0) # Make a 2-layer LCC raster (copy template twice) LCC <- c(r, r) names(LCC) <- c("LCC1", "LCC2") # A data.table with pixel indices and two non-forest columns dt <- data.table( pixelID = c(2, 3, 4, 5, 7, 8, 9), NF1 = c(1, 0, 0, 2, 0, 0, 1), NF2 = c(0, 1, 0, 0, 0, 3, 0) ) # Age vector indexed by cell ID (length ncell(LCC)) ages <- seq_len(ncell(LCC)) * 5 # toy ages out <- calcNonForestYoungAge( landcoverDT = dt, NFTSD = ages, LCCras = LCC, cutoffForYoungAge = 15 ) out names(out) # "LCC1" "LCC2" "youngAge" plot(out$youngAge) ## End(Not run)
youngAge column in FS covariatesDeprecated: use youngAgeAtYear(). This one treats NA ages as young, only sees the fires
in fireBufferedListDT (those being fitted), and needs a raster copy per year.
calcYoungAge( years, annualCovariates, standAgeMap, fireBufferedListDT, cutoffForYoungAge = fireSenseYoungAgeCutoff )calcYoungAge( years, annualCovariates, standAgeMap, fireBufferedListDT, cutoffForYoungAge = fireSenseYoungAgeCutoff )
years |
the years over which to iterate |
annualCovariates |
list of data.table objects with |
standAgeMap |
template |
fireBufferedListDT |
data.table containing non-annual burn and buffer |
cutoffForYoungAge |
Numeric. Default is 15. This is the age below which the pixel is considered
"young" –> |
a raster layer with unified stand age and time-since-disturbance values
preparing covariates for fitting modules
castCohortData( cohortData, pixelGroupMap, lcc, ageMap = NULL, missingLCC, year = NULL, cutoffForYoungAge = fireSenseYoungAgeCutoff )castCohortData( cohortData, pixelGroupMap, lcc, ageMap = NULL, missingLCC, year = NULL, cutoffForYoungAge = fireSenseYoungAgeCutoff )
cohortData |
A |
pixelGroupMap |
A |
lcc |
data.table of dummified landcover |
ageMap |
a stand age map to assign ages to non-forest LCC used during predict |
missingLCC |
LCC class to assign forested pixels absent from |
year |
numeric representing the year represented by |
cutoffForYoungAge |
Numeric. Default is 15. This is the age below which the pixel is considered
"young" –> |
a trimmed cohortData with wide-layout and rows for every pixel in lcc
spreadFitRun
chk_duplicatedStartPixels enforces the invariant that no more than one
fire can be ignited in a given pixel within a single time interval. When
duplicate cells are detected it issues a warning and keeps only the
largest fire (by size) for each duplicated pixel.
chk_duplicatedStartPixels(cells, size) .doDataChecks(moduleName, envir, attribs, fml)chk_duplicatedStartPixels(cells, size) .doDataChecks(moduleName, envir, attribs, fml)
cells |
Integer vector of raster cell indices (pixel IDs) at which fires are scheduled to start. |
size |
Integer vector the same length as |
moduleName |
Character. Name of the calling SpaDES module, used as a prefix in any error messages thrown. |
envir |
An environment (typically a SpaDES module's |
attribs |
Character. Name of the data object being checked, included in error messages so the caller can identify which input failed. |
fml |
A model formula passed through to |
A list with two elements: loci (deduplicated cells) and
sizes (corresponding size values).
Called for its side effects. Throws an informative error if any check fails; returns invisibly otherwise.
Ranks fuel classes by total treed AGB over a single representative data year (the fit study
area), so fireSenseCovariatesCreate(fuelCovariates = "domSecWetland") can be told the same
domClass/secClass for every data year of a fit, instead of choosing independently
(and possibly differently) each time it is called. Ties are broken alphabetically by fuel-class
name for a deterministic result.
chooseDomSecFuelClasses( cohortData, pixelGroupMap, flammableRTM, landcoverDT, sppEquiv, fuelClassCol, sppEquivCol, cutoffForYoungAge, requiredFuelClasses = NULL )chooseDomSecFuelClasses( cohortData, pixelGroupMap, flammableRTM, landcoverDT, sppEquiv, fuelClassCol, sppEquivCol, cutoffForYoungAge, requiredFuelClasses = NULL )
cohortData |
A |
pixelGroupMap |
A |
flammableRTM |
a |
landcoverDT |
As in |
sppEquiv |
table with species name equivalencies between the kNN and final naming formats.
See |
fuelClassCol |
As in |
sppEquivCol |
the column name to use from |
cutoffForYoungAge |
As in |
requiredFuelClasses |
As in |
list with domClass and secClass (character); secClass is NA when fewer than two
fuel classes are present, and both are NA when there are none (e.g. an ELF with no tree
species at all).
Map
Ensure fire points are located on flammable pixels inside a fire polygon
Intended to be run using Map
cleanUpSpreadFirePoints(firePoints, bufferDT, flammableRTM, idCol)cleanUpSpreadFirePoints(firePoints, bufferDT, flammableRTM, idCol)
firePoints |
a |
bufferDT |
a data.table of burned cells, output from |
flammableRTM |
a |
idCol |
Character. Name of the column in |
a list of harmonized points and polygons
climateCovRanges is the one table of fixed c(min, max) ranges, one per climate variable of the
spread model, that fireSense_spreadFit uses by default (its covFixedRange) instead of the range of
each ELF's data, so a coefficient means the same thing in every ELF. The variables and their units:
CMD, CMDsm and CMDsp are climate moisture deficit in mm (annual, summer-to-date and spring);
cumMDC is a cumulative Monthly Drought Code, an index with no unit (it is not mm). The values are
provisional: all four are 0-100 for now, to be replaced after the cumMDC values have been checked.
A climate covariate selected for the spread fit that is not in this table stops the fit; add its range
here.
climateCovRangesclimateCovRanges
A named list of c(min, max).
Converts stacks of climate rasters to data.table and optionally subsets to index
climateRasterToDataTable(historicalClimateRasters, Index = NULL)climateRasterToDataTable(historicalClimateRasters, Index = NULL)
historicalClimateRasters |
named list of |
Index |
optional list of |
a long-layout data.table of climate values in each pixel and year, at full precision: the
x1000 integer storage (toX1000()) is where they are rounded, as fireSense_spreadPredict does, so a
value is stored as the same integer in the fit and in the prediction
pixelGroups by flammabilityClassify pixelGroups by flammability
cohortsToFuelClasses( cohortData, pixelGroupMap, flammableRTM, landcoverDT = NULL, sppEquiv, sppEquivCol, cutoffForYoungAge, fuelClassCol = fireSenseFuelClassCol, requiredFuelClasses, asTable = FALSE )cohortsToFuelClasses( cohortData, pixelGroupMap, flammableRTM, landcoverDT = NULL, sppEquiv, sppEquivCol, cutoffForYoungAge, fuelClassCol = fireSenseFuelClassCol, requiredFuelClasses, asTable = FALSE )
cohortData |
A |
pixelGroupMap |
A |
flammableRTM |
a |
landcoverDT |
Optional table of non-forest land cover classes and pixel indices.
It will override pixel values in |
sppEquiv |
table with species name equivalencies between the kNN and final naming formats.
See |
sppEquivCol |
the column name to use from |
cutoffForYoungAge |
age at and below which pixels are considered 'young' |
fuelClassCol |
the column in |
requiredFuelClasses |
A character vector of all the fuel classes that are expected. This is needed because a fuel class may disappear (e.g., Popu_tre) due to succession, causing a downstream failure because the prediction model requires values for it. |
asTable |
if |
a SpatRaster of biomass by fuel class as determined by fuelClassCol and cohortData
(or a data.table, see asTable).
Merging and assignment of fuel classes
combine_fuel_classes(df, targetFuelClasses = 5, lowThreshold = 0.05)combine_fuel_classes(df, targetFuelClasses = 5, lowThreshold = 0.05)
df |
created during |
targetFuelClasses |
the number of classes at which to stop further merging |
lowThreshold |
species with |
a data.table with assigned fuel classes for each species
A size merge covers every ELF in its members, so a fire-count merge whose members are all in one is
replaced by it. Skips stay. The size merges get the fire counts of their members from status.
combinePlans(firePlan, sizePlan, status)combinePlans(firePlan, sizePlan, status)
firePlan |
Plan from |
sizePlan |
Plan from |
status |
|
A data.table in ELFmergePlan()'s format.
data.frame
Convert covariates to/from integers for smaller footprint; make data.frame
covsX1000AndSetDF( annualList, nonAnnualList, fireBufferedList, fireLociList, paramOrder, toX1000Integer = TRUE )covsX1000AndSetDF( annualList, nonAnnualList, fireBufferedList, fireLociList, paramOrder, toX1000Integer = TRUE )
annualList |
Named list of |
nonAnnualList |
Named list of |
fireBufferedList |
Named list of |
fireLociList |
Named list of |
paramOrder |
Character vector of the order of covariates that will be used. |
toX1000Integer |
Logical. If |
a data.table with relevant columns made mutually exclusive
The one rule for matching a year to a vegetation or land-cover data year: the data year closest
to, and not after, the year. fireSense_dataPrepFit assigns each fire year its data year with it
and decides a fit's model structure on it; fireSense_dataPrepPredict takes the vegetation of
time(sim) with it; so a fit and every prediction, hindcast or forecast, read the same data for
the same year.
dataYearFor(dataYears, years) dataYearElement(x, year)dataYearFor(dataYears, years) dataYearElement(x, year)
dataYears |
integer years with data, in any order. |
years |
integer years. |
x |
a list (anything with names) with one element per data year, named |
year |
one integer year. |
dataYearFor(): integer, one data year per element of years. Stops if a year precedes
the first data year: it has no vegetation data.
dataYearElement(): the name of the element of x that year uses, the one of
dataYearFor(<the years in names(x)>, year).
dataYearFor(c(1985, 1990, 2000, 2010, 2020), c(1985, 1999, 2015, 2024)) dataYearElement(list(year2010 = "a", year2020 = "b"), 2015)dataYearFor(c(1985, 1990, 2000, 2010, 2020), c(1985, 1999, 2015, 2024)) dataYearElement(list(year2010 = "a", year2020 = "b"), 2015)
The years of fire records that fireSense_dataPrepFit fits to, and over which
fireSense_ELFs counts fires to merge ELFs with too few of them. Both modules take
their fireYears default from here so that the ELFs and the fit always use the
same years.
defaultFireYears()defaultFireYears()
The years run from 1986, the year after the first SCANFI V2 year (1985), to the latest
year with historical climate for every tile (climateData::latestHistoricalYear());
climate is the last of the inputs to reach a year. A fire year is fitted against the latest
vegetation year strictly before it (the vegetation of year Y already shows year Y's burns),
so 1985 has no vegetation to pair with.
An integer vector of years.
The number of workers, and so the DEoptim population NP, runDEoptim() asks for when
nCoresNeeded is NULL: 20 + 10 * floor((nParams + 2) / 5), i.e. 30 for 4 to 7 parameters,
40 for 8 to 12 and 50 for 13 to 15. Ten times the number of parameters was tested against other
sizes; 40 was a good middle with very little improvement above it, and the current spread ledgers
have 10 to 12 parameters, so every current ELF gets 40.
deoptimPopulationSize(nParams)deoptimPopulationSize(nParams)
nParams |
Integer. The number of parameters estimated ( |
An integer.
NAs in a data.table with zerosModifies DT in place: for each column in colsToUse, every NA is
overwritten with 0 via data.table::set(). Useful when a covariate
table is later passed to a model that does not tolerate NAs.
dtReplaceNAwith0(DT, colsToUse = NULL)dtReplaceNAwith0(DT, colsToUse = NULL)
DT |
A |
colsToUse |
Character vector of column names in |
DT, invisibly modified by reference; columns are unchanged
where no NAs were present.
Counts natural-cause ignitions, escaped natural ignitions and fire polygons falling in
each ELF's fitting area (core plus buffer), per year. An escaped ignition is one that
escapedFires() keeps: the escape and spread fits use only these.
ELFfireCounts( rasWhole, firePoints, firePolys, fireYears, pixelAreaHa, naturalCauses = c("L", "N"), escapeSizeHa = 50, overlay = NULL )ELFfireCounts( rasWhole, firePoints, firePolys, fireYears, pixelAreaHa, naturalCauses = c("L", "N"), escapeSizeHa = 50, overlay = NULL )
rasWhole |
|
firePoints |
|
firePolys |
|
fireYears |
integer vector of the years being fitted. |
pixelAreaHa |
area of one fitting pixel, in hectares. A polygon counts when its area inside the ELF exceeds this. |
naturalCauses |
causes treated as natural ignitions. |
escapeSizeHa |
size (ha) a fire must reach to count as escaped, as in |
overlay |
the table from |
Points are counted on the grid of rasWhole with a single terra::cellFromXY()
lookup. Polygons are intersected with each ELF's area and their clipped area is
compared with pixelAreaHa, mirroring the size filter the spread fit applies
(fireSense_dataPrepFit.R:966-982).
A data.table with one row per ELF and year: ELF, year,
naturalIgnitions, escapes, firePolygons.
Intersects the fire polygons with each ELF's fitting area (core plus buffer) and with its core, and
returns one row per clipped piece. ELFfireCounts() counts the pieces larger than a pixel in the
fitting area, and ELFregionStats() sums the core pieces into a burn rate, so the slow intersection
is done once for both. A polygon wholly inside a zone is not clipped; only those crossing its edge
are, which is most of the saving.
ELFfireOverlay(rasWhole, firePolys, fireYears)ELFfireOverlay(rasWhole, firePolys, fireYears)
rasWhole |
|
firePolys |
|
fireYears |
integer vector of the years to keep. |
A data.table: ELF, zone ("fit" for core plus buffer, "core"), YEAR and ha, the
geodesic area of the piece. ELFs no polygon reaches have no rows.
An ELF with no natural ignitions, or no fire polygons, over the whole fitting window
cannot be fitted and is "zero". One below any threshold is "few": it can be
fitted, but the thin end of the data drives the escape model's 5-fold CV
(fireSense_ignitionFit.R:463,889), which needs at least 10 ignited cell-years
before some fold is left holding a single row. The escape and spread fits use only escaped
fires (see escapedFires()), so an ELF with many small fires and few large ones is "few"
through minEscapes.
ELFfitStatus( counts, minNaturalIgnitions = 50, minFirePolygons = 50, minEscapes = 5 )ELFfitStatus( counts, minNaturalIgnitions = 50, minFirePolygons = 50, minEscapes = 5 )
counts |
|
minNaturalIgnitions, minFirePolygons, minEscapes
|
thresholds below which an ELF is |
A data.table with one row per ELF: ELF, naturalIgnitions, escapes,
firePolygons, yearsWithFire, status ("zero", "few" or "ok").
Counts the land-cover pixels an ELF has that the fit would treat as flammable, i.e.
those not in nonflammableLCC. Unclassified cover (VLCE2 code 0) is nonflammable
by default, which is why ELFs outside VLCE2's mapped extent measure at or near zero
(8.2, 10.3.2 and 3.2.4 are 0; no-tree-elfs.md §2, elf-8.2-ecoregion.md).
ELFflammableArea(rasWhole, rstLCC, nonflammableLCC = fireSenseNonflammableLCC)ELFflammableArea(rasWhole, rstLCC, nonflammableLCC = fireSenseNonflammableLCC)
rasWhole |
|
rstLCC |
|
nonflammableLCC |
land-cover codes that cannot burn. The default,
fireSenseNonflammableLCC, matches |
This does not gate anything. Per Eliot's 2026-09-11 decision there is no
flammable floor – fireSense_spreadFit is allowed to try regardless – so the result
is a report, and an input to deciding whether merging an ELF with a neighbour would
give it enough to fit.
A data.table with one row per ELF: ELF, flammablePixels,
totalPixels, flammableFraction, flammableAreaHa.
Text to print on ELFs
elfLabels(ids, labels = c("code", "name", "none"))elfLabels(ids, labels = c("code", "name", "none"))
ids |
Character. ELF codes, e.g. |
labels |
|
A character vector the length of ids.
elfLabels(c("13.1", "5.4", "6.2.1", "6.2.2"), "name")elfLabels(c("13.1", "5.4", "6.2.1", "6.2.2"), "name")
Name of a merged ELF
ELFmergedName(members)ELFmergedName(members)
members |
ids of the ELFs being merged; they must share one base. |
The shared base followed by the members' last parts in numeric order, e.g.
c("3.2.4", "3.2.1") gives "3.2.1_4" and c("12.2", "12.1") gives "12.1_2".
Every ELF that ELFfitStatus() calls "zero" or "few" is considered once, in ELF order. Its
partner is the neighbouring ELF with the same base and the same depth – another piece of the
same split ecoprovince, or another whole ecoprovince of the same ecozone – that shares the
longest core border (ties: more fires, then ELF order) and is not already part of a merge. If
the two together reach all three thresholds they are merged; otherwise neither is fitted. An ELF with
no such neighbour is not fitted.
ELFmergePlan( status, neighbours, minNaturalIgnitions = 50, minFirePolygons = 50, minEscapes = 5 )ELFmergePlan( status, neighbours, minNaturalIgnitions = 50, minFirePolygons = 50, minEscapes = 5 )
status |
|
neighbours |
|
minNaturalIgnitions, minFirePolygons, minEscapes
|
thresholds a merged ELF must reach, as in
|
A data.table with one row per decision: action ("merge" or "skip"), ELF (the
merged ELF's name, NA for a skip), members (list of the ELF ids involved),
naturalIgnitions, escapes and firePolygons (their totals) and reason.
Measures how much core border each pair of ELFs shares on the common grid of rasWhole: the
number of horizontally or vertically adjacent cell pairs where one cell is core (2) in one
ELF and the other is core in the other.
ELFneighbours(rasWhole)ELFneighbours(rasWhole)
rasWhole |
ELF layers on one common grid, as a multi-layer |
A data.table with one row per pair of ELFs whose cores touch: ELF1, ELF2,
sharedEdges (cell edges) and sharedLength (in the grid's map units).
Statistics for ELFsizePlan(). A region is the core (cells equal to 2) of one layer of rasWhole.
Land-cover shares come from a regular grid of up to maxSample points in the core, so the result is
deterministic. The burn rate is the area of firePolys inside the core, as a percentage of the core per year.
ELFregionStats( rasWhole, landCover, firePolys = NULL, fireYears = NULL, classes = c(20, 30, 40, 50, 100, 210, 220, 230), maxSample = 20000L, overlay = NULL, members = NULL )ELFregionStats( rasWhole, landCover, firePolys = NULL, fireYears = NULL, classes = c(20, 30, 40, 50, 100, 210, 220, 230), maxSample = 20000L, overlay = NULL, members = NULL )
rasWhole |
|
landCover |
|
firePolys |
|
fireYears |
years over which |
classes |
land-cover codes whose shares are returned. The default is SCANFI's: water, rock, bryoids, shrubs, herbs, coniferous, broadleaf, mixedwood. |
maxSample |
largest number of sample points per region. |
overlay |
table from |
members |
named list giving, for each region (name of a layer of |
A data.table with one row per region: ELF, areaKm2, burnRate (%/yr) and landCover
(list column of named numeric vectors of shares, names classes).
The ELF to run for an ELF id
ELFrunName(ELF, plan)ELFrunName(ELF, plan)
ELF |
an ELF id. |
plan |
|
The merged ELF's name if ELF was merged, otherwise ELF.
ELFs of ecozones 1 and 2 (ids 1.* and 2.*) are never fitted: runELFs() leaves them out of
every list and map, and ELFmergePlan() neither merges them nor uses them as partners.
ELFsArctic(ids)ELFsArctic(ids)
ids |
ELF ids. |
The ids in ids that are left out.
ELFs that cannot be fitted
ELFsExcluded(status)ELFsExcluded(status)
status |
|
character vector of ELF names with status "zero".
Intersects a study area with a set of Ecologically-based Low
Fractal-dimensional (ELF) polygons, identifies which ELFs overlap the study
area, and constructs a single categorical raster combining each ELF's
per-cell classification. A cell in an ELF's core (2) is labelled with that
ELF. A cell in the buffer (1) of one or more ELFs is labelled with the ELF,
among those, whose core is nearest. All other in-domain cells are 0.
ELFsInStudyArea(studyArea, inputPath, ELFsRaster = NULL, ELFsPolygon = NULL)ELFsInStudyArea(studyArea, inputPath, ELFsRaster = NULL, ELFsPolygon = NULL)
studyArea |
A |
inputPath |
Character. Directory in which to store any downloads
produced by |
ELFsRaster |
Optional named list (one entry per ELF) of |
ELFsPolygon |
Optional |
The function assumes that ELFs (a list-like object with rasWhole rasters
and an ID field) and rastTemplate are available in the calling
environment, along with inputPath. ELF rasters are expected to contain the
integer values 0, 1, and 2, where 2 indicates the core area of the ELF
and 1 indicates the buffer for that ELF.
The three layers are combined with terra::cover() so that:
cores override everything else,
a buffer cell takes the ELF with the nearest core (terra::distance()), and
the 0 background fills remaining in-domain cells.
A categorical SpatRaster with a value/ELFind levels table,
where ELFind gives the ELF identifier (or "none" for background).
makeELFs(), terra::distance(), terra::mosaic(),
terra::cover()
A region with areaKm2 < minAreaKm2 is small. Its candidate partners are the neighbours of the same
group whose land-cover (Bray-Curtis) distance is at most maxLandCoverDist and whose burn-rate ratio
(larger over smaller) is at most maxBurnRatio. For each candidate the merge is simulated (areas summed,
land cover and burn rate weighted by area, neighbours combined) and the small regions left with no
candidate partner, the orphans, are counted. The candidate with the fewest orphans is accepted, ties
going to the smaller land-cover distance and then the smaller burn ratio. This repeats until no candidate
is left, so a merged region that is still small can merge again and a group can grow beyond two regions.
ELFsizePlan( stats, neighbours, minAreaKm2 = 35000, maxLandCoverDist = 0.35, maxBurnRatio = 6, group = .ELFparent )ELFsizePlan( stats, neighbours, minAreaKm2 = 35000, maxLandCoverDist = 0.35, maxBurnRatio = 6, group = .ELFparent )
stats |
|
neighbours |
|
minAreaKm2 |
regions with a smaller core area are small. |
maxLandCoverDist, maxBurnRatio
|
the similarity limits above. |
group |
function of the region ids giving the group within which regions may merge. The default
is the ELF base ( |
A data.table with one row per merged region, as ELFmergePlan() returns for merges: action
("merge"), ELF (the merged name), members (list of the original ids) and reason, plus areaKm2.
mergeELFs() applies it. Zero rows if nothing merges.
ELFs not fitted after merging
ELFsSkipped(plan)ELFsSkipped(plan)
plan |
|
character vector of the ELF ids in the plan's skip decisions.
Downloads the SCANFI Douglas-fir raster (by default the v2 2020 file on the
Arbutus object store), aggregates it by a factor of 8, turns it into a 1/NA
mask, loads it into memory, and writes it to disk as a reusable template for
building Ecologically-based Low Fractal-dimensional (ELF) objects. Both the
remote download and the aggregation step are cached via reproducible::Cache(),
keyed on url and the remote file's hash, so the template is only rebuilt when
the source changes.
ELFtemplateRaster( inputPath, url = "https://object-arbutus.alliancecan.ca/529feda02d404836b0e91b1d360b4df0:predictiveecology/SCANFI_v2/2020/SCANFI_spsCC_PSEU_MEN_2020_v2_20260119.tif" )ELFtemplateRaster( inputPath, url = "https://object-arbutus.alliancecan.ca/529feda02d404836b0e91b1d360b4df0:predictiveecology/SCANFI_v2/2020/SCANFI_spsCC_PSEU_MEN_2020_v2_20260119.tif" )
inputPath |
Character. Directory in which to store the downloaded
source raster and the resulting |
url |
Character. The source raster. It is used only for its footprint
and grid, so any SCANFI layer with the national extent will do. The default
is the v2 Douglas-fir 2020 file, which has the same extent, 30 m
resolution and CRS as the v1.2 file on |
The Douglas-fir layer is used purely for its spatial footprint and grid, so
the returned values are a mask, not cover. At fact = 8, the v1.2 file has
156,026,794 non-NA cells and the v2 file 156,482,565; 460,121 cells are NA
only in v1.2 and 4,350 only in v2, so ELF maps and rasterToMatch built from
the template differ by about 0.3% of cells between the two.
Remote metadata is checked at most once per week
(notOlderThan = Sys.time() - 60*60*24*7) to avoid unnecessary network
calls.
A SpatRaster pointing to rastTemplate_Canada.tif inside
inputPath. The raster covers Canada at roughly 8x the native SCANFI
resolution; it is 1 where the aggregated source has data (including zero
cover) and NA elsewhere, and is suitable as a template for downstream ELF
construction.
reproducible::prepInputs(), reproducible::Cache(),
terra::aggregate(), terra::writeRaster()
A covariate is empty when it is zero everywhere, or, for fuel biomass, when it is on the
logMinB() floor everywhere: fuel is stored as log biomass, so a class with no biomass in the
buffers is 3.6 everywhere, not 0. The floor is recognised by its value, so the test does not
depend on how a column is named. An indicator with any 1, or a fuel class with any biomass, is not empty.
NAs are ignored, as colSums(na.rm = TRUE) did.
emptySpreadCovariates(dt, cols)emptySpreadCovariates(dt, cols)
dt |
|
cols |
character vector: the columns of |
the names among cols that are empty.
Fires that escaped
escapedFires(fires, escapeSizeHa, pixSizeHa, sizeCol = "SIZE_HA")escapedFires(fires, escapeSizeHa, pixSizeHa, sizeCol = "SIZE_HA")
fires |
Fire points or polygons ( |
escapeSizeHa |
Size (ha) a fire must reach to count as escaped. |
pixSizeHa |
Pixel area (ha). A fire must also be larger than one pixel. |
sizeCol |
The size column. |
The rows of fires that escaped.
The smallest whole number of pixels whose area is at least escapeSizeHa. Shared by the spread
fit (.objfunSpreadFit()) and fireSense's burning, so "escaped" means the same in both.
escapeSizePixels(escapeSizeHa, landscape)escapeSizePixels(escapeSizeHa, landscape)
escapeSizeHa |
Size (ha) a fire must reach to count as escaped. |
landscape |
A |
An integer, at least 1.
r <- terra::rast(nrows = 10, ncols = 10, xmin = 0, xmax = 2400, ymin = 0, ymax = 2400) escapeSizePixels(50, r) # 240 m pixels are 5.76 ha: 9 pixelsr <- terra::rast(nrows = 10, ncols = 10, xmin = 0, xmax = 2400, ymin = 0, ymax = 2400) escapeSizePixels(50, r) # 240 m pixels are 5.76 ha: 9 pixels
Merges each ELF with too few fires with a neighbour that shares its base (ELFmergePlan()), then each
region still smaller than minRegionAreaKm2 with a similar neighbour (ELFsizePlan()). Arctic ELFs
(ELFsArctic()) are neither counted nor merged.
fewFireELFs( ELFs, fireYears, pixelAreaHa, destinationPath, nfdbUrl = nfdbPointUrl(), nbacUrl = latestNBACUrl(), minNaturalIgnitions = 50, minFirePolygons = 50, escapeSizeHa = 50, minEscapes = 5, landCoverFile = NULL, minRegionAreaKm2 = 35000, maxLandCoverDist = 0.35, maxBurnRatio = 6 )fewFireELFs( ELFs, fireYears, pixelAreaHa, destinationPath, nfdbUrl = nfdbPointUrl(), nbacUrl = latestNBACUrl(), minNaturalIgnitions = 50, minFirePolygons = 50, escapeSizeHa = 50, minEscapes = 5, landCoverFile = NULL, minRegionAreaKm2 = 35000, maxLandCoverDist = 0.35, maxBurnRatio = 6 )
ELFs |
List from |
fireYears |
Integer vector of years to count fires over. |
pixelAreaHa |
Area of one pixel of the ELF rasters, in ha. |
destinationPath |
Directory the fire records are downloaded to. |
nfdbUrl, nbacUrl
|
URLs of the NFDB point and NBAC polygon archives. |
minNaturalIgnitions |
Fewer natural-cause ignitions than this is too few. |
minFirePolygons |
Fewer fire polygons than this is too few. |
escapeSizeHa |
Size (ha) a fire must reach to count as escaped. |
minEscapes |
Fewer escaped natural fires than this is too few. |
landCoverFile |
Path to a land-cover map in class codes (SCANFI's), or |
minRegionAreaKm2 |
After the fire-count plan, regions with a core smaller than this (km2) are merged
with a similar neighbour. |
maxLandCoverDist, maxBurnRatio
|
How similar a neighbour must be for the size rule: largest land-cover (Bray-Curtis) distance and largest burn-rate ratio. |
The fire records are read with reproducible::prepInputs(), which caches them, and the clipped fire
polygons of every ELF (ELFfireOverlay(), the slow step) are cached on the ELF maps, the NBAC release
and fireYears, so a change to the plan rules does not repeat either.
List: ELFs (the merged maps), status (ELFfitStatus()), plan (the fire-count and size
merges and the skips, in ELFmergePlan()'s format) and excluded (names of ELFs not fitted).
Turns fire polygons or a fire-year raster into the per-year pixel lists
youngAgeAtYear() reads. Polygons are rasterized at cell centres, as makeTSD() does.
firePixelsByYear(firePolys = NULL, fireRaster = NULL, template = NULL)firePixelsByYear(firePolys = NULL, fireRaster = NULL, template = NULL)
firePolys |
list named by year ( |
fireRaster |
|
template |
|
list named by year ("2001") of integer pixelIDs; years with no burned pixel are
absent.
Downloads the archive if needed. The shapefile's name carries the release, so callers key their Cache on the name.
fireRecordShapefile(url, destinationPath, ...)fireRecordShapefile(url, destinationPath, ...)
url |
URL of the archive. |
destinationPath |
Directory to download and extract into. |
... |
Passed to |
Character path(s) of the .shp file(s) in the archive.
Download the FireSense parameter object, strip the list columns and convert to a SpatVector or SpatRaster.
fireSenseCloudParameters( url = paste0("https://drive.google.com/file/d/", "1oJX7V5wPSj49C6wt59yD9RBplfZ7Cp-f/view?usp=drive_link"), targetFile = "fireSenseParams.rds", destinationPath = ".", useCache = TRUE )fireSenseCloudParameters( url = paste0("https://drive.google.com/file/d/", "1oJX7V5wPSj49C6wt59yD9RBplfZ7Cp-f/view?usp=drive_link"), targetFile = "fireSenseParams.rds", destinationPath = ".", useCache = TRUE )
url |
Http url of the fireSense object with parameters on Google Drive:
either the file itself (the default) or the folder that contains |
targetFile |
The name of the file to find when |
destinationPath |
A path where a copy of the downloaded file is saved. |
useCache |
Ignored. Kept so existing calls still work: the file is always downloaded fresh. |
The file is downloaded from Google Drive on every call, so the result is always the current state of the shared parameter file, never a copy left on disk by an earlier call.
The object and the rds file saved to destinationPath.
Download the FireSense parameter object, strip the list columns and
convert to a SpatVector or SpatRaster. If plot = TRUE, this will also
download a map that represents the forested lands of canada, to be plotted
on the plot device with the fireSense parameter ELFs that currently have
estimated parameters.
fireSenseCloudParametersMap(rasterize = FALSE, plot = TRUE, res = 5000, ...)fireSenseCloudParametersMap(rasterize = FALSE, plot = TRUE, res = 5000, ...)
rasterize |
Logical. If |
plot |
Logical. If |
res |
The resolution of the raster if |
... |
Other parameters passed to |
The map, either SpatRaster or SpatVector
Constructs pixel-level covariates required by FireSense (e.g., mutually
exclusive fuel-class indicators, transformed by logMinB, and a
youngAge indicator) by combining cohort-derived fuel classes with
land cover, flammability, and (optionally) non-forest time-since-disturbance.
fireSenseCovariatesCreate( cohortData, pixelGroupMap, flammableRTM, sppEquiv, landcoverDT, fuelClassCol, requiredFuelClasses = NULL, sppEquivCol, missingLCCgroup, nonForestedLCCGroups, nonForest_timeSinceDisturbance, cutoffForYoungAge, nonForestCanBeYoungAge, studyAreaName, useCache = TRUE, rstLCC = NULL, treedWetlandLCC = 81, treedWetland = TRUE, fuelCovariates = c("species", "domSecWetland"), domClass = NULL, secClass = NULL, youngAge = TRUE, fuelClassTable = NULL )fireSenseCovariatesCreate( cohortData, pixelGroupMap, flammableRTM, sppEquiv, landcoverDT, fuelClassCol, requiredFuelClasses = NULL, sppEquivCol, missingLCCgroup, nonForestedLCCGroups, nonForest_timeSinceDisturbance, cutoffForYoungAge, nonForestCanBeYoungAge, studyAreaName, useCache = TRUE, rstLCC = NULL, treedWetlandLCC = 81, treedWetland = TRUE, fuelCovariates = c("species", "domSecWetland"), domClass = NULL, secClass = NULL, youngAge = TRUE, fuelClassTable = NULL )
cohortData |
|
pixelGroupMap |
A raster (SpatRaster) or mapping structure linking cohort groups to pixels. |
flammableRTM |
A raster (SpatRaster) mask of flammable pixels (non-flammable typically |
sppEquiv |
Species equivalency table used to map species codes to fuel-class groupings. |
landcoverDT |
|
fuelClassCol |
Character name of the fuel-class column produced/expected by |
requiredFuelClasses |
A character vector of all the fuel classes that are expected. This is needed because a fuel class may disappear (e.g., Popu_tre) due to succession, causing a downstream failure because the prediction model requires values for it. |
sppEquivCol |
Character name of the species-equivalency column in |
missingLCCgroup |
A single unquoted column name (passed to |
nonForestedLCCGroups |
Named vector or list where names correspond to the non-forest land-cover
columns in |
nonForest_timeSinceDisturbance |
A raster/vector of time-since-disturbance (TSD) for non-forest pixels;
indexed by |
cutoffForYoungAge |
Numeric threshold (years). Pixels with TSD |
nonForestCanBeYoungAge |
Logical. If |
studyAreaName |
Character tag used for caching/user tags. |
useCache |
Logical. If |
rstLCC |
Optional land-cover |
treedWetlandLCC |
Land-cover code(s) of treed wetland. Default 81 (NTEMS; also what
|
treedWetland |
Logical. |
fuelCovariates |
|
domClass, secClass
|
Only used when |
youngAge |
logical. |
fuelClassTable |
Optional, the result of |
The function:
Calls cohortsToFuelClasses() to derive fuel-class rasters from cohorts.
Converts these to a long data table keyed by pixelID and joins to landcoverDT.
Verifies there are no NA values across covariate columns and raises an error otherwise.
Marks pixels with all-zero covariates as the provided missingLCCgroup.
Enforces mutual exclusivity among the specified fuel/landcover columns.
Applies logMinB to all fuel-class columns (excluding youngAge).
If nonForestCanBeYoungAge = TRUE, augments youngAge for non-forest pixels
using nonForest_timeSinceDisturbance and the cutoffForYoungAge.
All covariate columns must be non-NA; the function stops with an error if any NA
are detected after joining fuelClasses and landcoverDT.
Pixels where all covariates sum to zero are flagged by setting missingLCCgroup := 1.
When nonForestCanBeYoungAge = TRUE, youngAge for non-forest is derived using
nonForest_timeSinceDisturbance and cutoffForYoungAge. Any existing youngAge
from fuel classes is combined with this non-forest contribution.
Once youngAge is final, mutual exclusivity is enforced via makeMutuallyExclusive()
using all fuel-class columns, the land-cover columns (excluding pixelID) and
treedWetland (if rstLCC is supplied); youngAge is made exclusive to them.
Fuel-class columns (excluding youngAge) are transformed with logMinB.
When fuelCovariates = "domSecWetland", the per-species fuel-class columns are
collapsed to dom_agb_*, sec_agb_* (other classes are dropped; and
treedWetland_agb, if rstLCC is supplied) before mutual exclusivity and
logMinB are applied to them, exactly as for the per-species columns.
A data.table named spreadCovariates containing one row per pixelID, with:
Mutually exclusive fuel-class covariate columns (log-transformed by logMinB).
Land-cover indicator columns from landcoverDT.
A youngAge indicator (possibly augmented by non-forest TSD logic).
fuelClasses returned by cohortsToFuelClasses() includes one column per fuel class,
plus optionally youngAge, and a cell (renamed to pixelID here).
landcoverDT must contain a pixelID column aligned to rasters by cell index.
nonForestedLCCGroups names correspond to column names in landcoverDT.
nonForest_timeSinceDisturbance is indexable by pixelID (e.g., vector aligned to raster cells).
cohortsToFuelClasses, makeMutuallyExclusive,
logMinB, putBackIntoRaster, calcNonForestYoungAge
## Not run: covs <- fireSenseCovariatesCreate( cohortData = cohortsDT, pixelGroupMap = pgRas, flammableRTM = flammRas, sppEquiv = sppEquivDT, landcoverDT = landcoverDT, fuelClassCol = "fuelClass", sppEquivCol = "sppEquivCol", missingLCCgroup = "LCC_missing", nonForestedLCCGroups = c(NonForest = 1), nonForest_timeSinceDisturbance = NF_TSD, cutoffForYoungAge = 20, nonForestCanBeYoungAge = TRUE, studyAreaName = "MyArea", useCache = TRUE ) ## End(Not run)## Not run: covs <- fireSenseCovariatesCreate( cohortData = cohortsDT, pixelGroupMap = pgRas, flammableRTM = flammRas, sppEquiv = sppEquivDT, landcoverDT = landcoverDT, fuelClassCol = "fuelClass", sppEquivCol = "sppEquivCol", missingLCCgroup = "LCC_missing", nonForestedLCCGroups = c(NonForest = 1), nonForest_timeSinceDisturbance = NF_TSD, cutoffForYoungAge = 20, nonForestCanBeYoungAge = TRUE, studyAreaName = "MyArea", useCache = TRUE ) ## End(Not run)
The single source of truth for which codes in the land cover built by
makeFireSenseLCC() are non-flammable. fireSense_dataPrepFit and
fireSense_dataPrepPredict take their nonflammableLCC parameter default from this
constant, and makeFireSenseLCC() and ELFflammableArea() take theirs from it too,
so the land cover a fit/prediction is built from and the land cover it is run on
cannot silently disagree on what counts as flammable.
fireSenseNonflammableLCCfireSenseNonflammableLCC
numeric vector, c(0, 20, 30, 31, 32, 33).
Every code below comes from makeFireSenseLCC()'s two land-cover sources,
LandR::prepInputs_NTEMS_LCC_FAO() and LandR::prepInputs_SCANFI_LCC_FAO()
(documented in the "Data codes" comment in LandR/R/prepInputs_NTEMS.R and
LandR/R/maps.R), plus SCANFI's raw-class recode in
LandR::convert_SCANFI_LCC_codes():
0: no data / unclassified – non-flammable.
20: water – non-flammable.
30: rock/exposed land, SCANFI's combined rock+exposed class
(LandR::convert_SCANFI_LCC_codes()) – non-flammable. This was missing from the
modules' old default, so SCANFI-derived rock entered fits as flammable non-forest.
31: snow/ice (NTEMS) – non-flammable.
32: rock/rubble (NTEMS) – non-flammable.
33: exposed/barren land (NTEMS) – non-flammable.
40: bryoids – flammable ground cover, not included.
50: shrubs – flammable, not included.
80, 81: wetland, wetland-treed – flammable, not included.
100: herbs – flammable, not included.
210, 220, 230: coniferous, broadleaf, mixedwood forest – flammable, not
included.
240: FAO-forest disturbed code (disturbedCode in
LandR::prepInputs_SCANFI_LCC_FAO()/LandR::prepInputs_NTEMS_LCC_FAO()) –
flammable forest, not included.
Character (or character-vector) constants used across the package and
downstream modules to keep column names, identifiers, and other free-text
tokens consistent. All such constants end in Txt.
polygonIDTxt: character(1). Name of the polygon-ID column
(currently "polygonID").
nonNFColNamesTxt: character vector of bookkeeping column names
that are not non-forest landcover classes (currently "pixelID"
and polygonIDTxt); used with base::setdiff() to select the
non-forest landcover columns when summing/aggregating across rows
(see makeTSD()).
yearTxt: character(1). Token used as a year-column name or as a
prefix on year-suffixed layer/column names (currently "year").
youngAgeTxt: character(1). Name of the "young-age" cohort class
(currently "youngAge").
ignitionsTxt: character(1). Name of the ignitions column
(currently "ignitions").
escapesTxt: character(1). Name of the escapes column
(currently "escapes").
spreadFitAdditionalColNamesTxt: character vector of extra
simList-slot/column names attached to spread-fit outputs
("numIterations", "objFunVal", "params", "sppEquiv",
"nonForestedLCCGroups", "missingLCCgroup", "covMinMax_spread"). covMinMax_spread is
what prediction needs to rescale covariates exactly as the fit did.
ignitionFitAdditionalColNamesTxt: character vector of the list-column names attached
to ignition-fit ledger rows ("fireSense_IgnitionFitted", "fireSense_EscapeFitted").
spreadInterceptTxt: character(1). Name of the spread model's intercept, in a formula's
design (spreadDesignCols()), in lower/upper and in a ledger row's params
(currently "(Intercept)", what stats::lm() calls it).
spreadFitCovCentreTxt: character(1). Name of the ledger column that holds the covariate
centres of a fit made with an intercept (currently "covCentre_spread"). It is not in
spreadFitAdditionalColNamesTxt: a fit without an intercept writes no such column.
treedWetlandAgbTxt: character(1). Name of the pooled treed-wetland biomass column
built by fireSenseCovariatesCreate(fuelCovariates = "domSecWetland") (currently
"treedWetland_agb").
The checks made by hand on the FireSense phase-2 fits (September 2026), as functions, so that
fireSense_spreadFit can make them after every fit.
spreadProbSummary(p, ceiling, tol = 0.002, binWidth = 0.001) combineSpreadProbSummaries(x) simulateFireSizes( pop, fn = .objfunSpreadFit, fnArgs = list(), cl = NULL, seed = 1L ) scoreFireSizes( sims, probs = c(0.01, 0.1, 0.25, 0.5, 0.75, 0.9, 0.99), largeFire = 174 ) linkSaturation(sims, probsP = c(0.01, 0.1, 0.25, 0.5, 0.75, 0.9, 0.99)) coefIdentifiability(pop, lower, upper, zMin = 1) profileCoefficients( best, pop, fn = .objfunSpreadFit, reps = 10L, cl = NULL, seed = 1L, fnArgs = list(), coefs = covariateCoefs(names(best)), probsPop = c(0.05, 0.25, 0.5, 0.75, 0.95) ) identifiedInIsolation(ident, profile, seMult = 2) fitConvergence(DE)spreadProbSummary(p, ceiling, tol = 0.002, binWidth = 0.001) combineSpreadProbSummaries(x) simulateFireSizes( pop, fn = .objfunSpreadFit, fnArgs = list(), cl = NULL, seed = 1L ) scoreFireSizes( sims, probs = c(0.01, 0.1, 0.25, 0.5, 0.75, 0.9, 0.99), largeFire = 174 ) linkSaturation(sims, probsP = c(0.01, 0.1, 0.25, 0.5, 0.75, 0.9, 0.99)) coefIdentifiability(pop, lower, upper, zMin = 1) profileCoefficients( best, pop, fn = .objfunSpreadFit, reps = 10L, cl = NULL, seed = 1L, fnArgs = list(), coefs = covariateCoefs(names(best)), probsPop = c(0.05, 0.25, 0.5, 0.75, 0.95) ) identifiedInIsolation(ident, profile, seMult = 2) fitConvergence(DE)
p |
Numeric. Spread probabilities. |
ceiling |
The link's upper asymptote, |
tol |
A probability within |
binWidth |
Width of the bins in which |
x |
A list of |
pop |
A matrix or |
fn |
The objective; |
fnArgs |
Named list of further arguments to |
cl |
A cluster, or |
seed |
Every parameter set is evaluated with the same seeds ( |
sims |
The output of |
probs |
Quantiles of fire size to compare. |
largeFire |
Size in pixels above which a fire counts as large (174 pixels = 1000 ha at 5.76 ha per pixel). |
probsP |
Quantiles of spread probability to report. |
lower, upper
|
The bounds the fit used, named as the columns of |
zMin |
The |
best |
Named numeric: the parameter set to profile around, normally the best member by
replicated mean ( |
reps |
Evaluations of each profile point. |
coefs |
The coefficients to profile; all covariate coefficients by default. |
probsPop |
Population quantiles to evaluate each coefficient at, besides 0. |
ident |
The output of |
profile |
The output of |
seMult |
Dropping a coefficient must worsen the objective by more than |
DE |
The output of |
simulateFireSizes() simulates the observed fires from each of several parameter sets, with
the "too burny" gate lifted, and returns the simulated sizes.
scoreFireSizes() compares those with the observed sizes: per fire, per year, and by
quantile. It never uses the objective's value.
linkSaturation() reports how many pixel-years sit at the spread-probability ceiling. When
most do, fire size is decided by the ceiling alone ("too many medium, too few large fires").
coefIdentifiability() measures, for each covariate coefficient, how tightly the final
population pins it down.
profileCoefficients() sets each coefficient in turn to 0 and to values across the
population's range, other coefficients held at the best member, and re-scores.
identifiedInIsolation() combines the two: a coefficient is identified in isolation when
the population pins its sign (zPop >= zMin) and dropping it (setting it to 0) makes the
objective clearly worse.
fitConvergence() summarises the objective across the fit's generations.
spreadProbSummary(): a list with n, atCeiling (a count), counts (per bin) and
binWidth.
combineSpreadProbSummaries(): their sum, as one summary.
simulateFireSizes(): a data.table, one row per parameter set x fire x replicate:
member (row of pop), yr, rep, initialLocus, ids, simulated sim and observed
size, in pixels. A year the objective will not simulate even with its gate lifted keeps its
fires with sim NA. attr(, "spreadProb") is a list of spreadProbSummary()s, one per
member.
scoreFireSizes(): a one-row data.table. fireBias and fireRMSE are the mean and
root mean square of log10(simulated / observed) per fire (0.3 is a factor of 2); year* the
same for annual area burned; yearIn90pct the share of years whose observed area lies within
the 5-95% range of simulated years; simsOver10xObs and simsUnderTenthObs the share of
simulated fires more than 10 times too large or too small; AD the Anderson-Darling statistic
between simulated and observed sizes; qObs_*/qSim_* the quantiles in probs.
linkSaturation(): a data.table, one row per member: pixelYears, propAtCeiling
and the spread-probability quantiles p_* (bin midpoints).
coefIdentifiability(): a data.table, one row per covariate coefficient: the
population median popMedian; spread90, the 5-95% range across members as a share of the
bound width; atBound, the share of members within 5% of the width from a bound;
zPop = |popMedian| / ((q95 - q5) / 3.29), the median in units of the population's spread
(a normal's 5-95% range is 3.29 sd); rSlope, the correlation across members with
hillSlope1 (the link uses hillSlope1 * X b, so the two trade off by construction; NA when
the population has no hillSlope1 column, as now that it is fixed at 1); and
signPinned = zPop >= zMin. With three runs each of four ELFs, zPop >= 1 found the
coefficients whose sign every run agreed on with 94% precision and 44% recall.
profileCoefficients(): a data.table, one row per coefficient x profile point: coef,
at (its value there; isZero marks the drop test), mean of the objective over reps, and
delta and deltaSE: the mean paired difference from best (same seeds) and its standard
error. A positive delta means the point fits worse than best. A reference row
(coef = "") holds best itself.
identifiedInIsolation(): ident with dropDelta, dropDeltaSE, dropMatters and
identified (signPinned & dropMatters) added.
fitConvergence(): a data.table, one row per chunk: generation (its last),
bestval (the best value so far) and the median and standard error of the median of the
population's values (fail values of 1e6 and above left out).
The folder that holds the spread-fit and ignition-fit ledger files (see
spreadFitFilenameFor() and ignitionFitFilenameFor()). The modules that write and read
the ledgers (fireSense_spreadFit, fireSense_ignitionFit, fireSense_dataPrepFit,
fireSense_ELFs) use these as the defaults of their spreadFitGoogleDriveFolder and
ignitionFitGoogleDriveFolder parameters, and latestSpreadFits() and
latestIgnitionFits() use them as the default cloudFolderID.
spreadFitLedgerFolder( folder = getOption("fireSenseUtils.spreadFitLedgerFolder", "https://drive.google.com/drive/folders/1X9-mRjyLMNpgkP_cfqhbr_AQEPOsVCHf") ) ignitionFitLedgerFolder( folder = getOption("fireSenseUtils.ignitionFitLedgerFolder", spreadFitLedgerFolder()) )spreadFitLedgerFolder( folder = getOption("fireSenseUtils.spreadFitLedgerFolder", "https://drive.google.com/drive/folders/1X9-mRjyLMNpgkP_cfqhbr_AQEPOsVCHf") ) ignitionFitLedgerFolder( folder = getOption("fireSenseUtils.ignitionFitLedgerFolder", spreadFitLedgerFolder()) )
folder |
The folder (url or id). An explicit value wins over the option. |
A character string, the folder's url or id.
To use another folder, set an option; every module and function then follows it.
fireSenseUtils.spreadFitLedgerFolderthe spread-fit ledger folder (url or id). Default: the shared folder of the fireSense project.
fireSenseUtils.ignitionFitLedgerFolderthe ignition-fit ledger folder (url or id). Default: the value of the spread-fit ledger folder, so one option moves both.
hillSlope1 and inflectionPoint1, in the position they take in the link, right after
maxAsymptote. DEoptim's par, lower and upper do not contain them; the objective, the
validation and the gates insert them (fixLogisticPars()), and fireSense_spreadFit restores them
in the ledger's parameter sets from this vector.
fixedLogisticParsfixedLogisticPars
A named numeric vector.
Calculate proportional burn of landcover and tree species
fuelClassPrep( pixelGroupMap, cohortData, rstLCC, nonflammableLCC, fires, nonforestLCC, yearRange )fuelClassPrep( pixelGroupMap, cohortData, rstLCC, nonflammableLCC, fires, nonforestLCC, yearRange )
pixelGroupMap |
A |
cohortData |
A |
rstLCC |
a landcover map |
nonflammableLCC |
nonflammable landcover in |
fires |
a single |
nonforestLCC |
vector or list of vectors of flammable non-forest LCC |
yearRange |
the range of years represented by this landscape |
data.table with cell, biomass, tree species or LCC for non-forest, and year of fire
# fuelClassPrep( # sim$pixelGroupMap2011, sim$cohortData2011, sim$rstLCC2011, # rstLCC = sim$rstLCC2011, nonForestLCC = sim$nonForestLCCGroups, # nonflammableLCC = P(sim)$nonflammableLCC, # fires = do.call(rbind, sim$spreadFirePolys), # yearRange = c(2012, 2020) # )# fuelClassPrep( # sim$pixelGroupMap2011, sim$cohortData2011, sim$rstLCC2011, # rstLCC = sim$rstLCC2011, nonForestLCC = sim$nonForestLCCGroups, # nonflammableLCC = P(sim)$nonflammableLCC, # fires = do.call(rbind, sim$spreadFirePolys), # yearRange = c(2012, 2020) # )
Fuel covariates of the spread model are biomass on the LINEAR scale, divided by a fixed
1e4. The division is not done to the data: it is the covMinMax given to
rescaleKnown2(), which is affine and does not clamp, so c(0, 1e4) is exactly
biomass / 1e4. The constant is fixed, not max(biomass), so that
fireSense_spreadPredict reproduces the fit's scaling in every year from the stored
covMinMax_spread alone. It is also how a fit is recognised as linear: see
isLinearFuelRange().
fuelLinearRangefuelLinearRange
fireSenseCovariatesCreate() returns fuel-class biomass as logMinB(): logged, with
everything below exp(log(100) - 1) (36.8) raised to that floor. On that scale the spread
model cannot use the fuel gradient: on ELF 5.3.2, 45% of pixels sit on the floor and the
treed ones fall in 16% of the covariate range (rescaled sd 0.05), so the coefficient
estimates little more than treed against treeless. On the linear scale the treed pixels
span twice the range and an absent fuel is exactly 0, so it contributes exactly nothing.
fuelLogToLinear(x)fuelLogToLinear(x)
x |
Numeric vector of fuel biomass as returned by |
This undoes the log where the spread model needs it, instead of removing it at the source,
because fireSenseCovariatesCreate() also builds the ignition covariates and its output is
cached for every fitted polygon. Both fireSense_spreadFit and fireSense_spreadPredict
call this function, so the fit and the prediction cannot drift apart.
Biomass on the linear scale; values on the logMinB() floor become 0.
SpatialPoints from Canadian Fire DatabaseGet Fire SpatialPoints from Canadian Fire Database
getFirePoints_NFDB( url = NULL, studyArea = NULL, rasterToMatch = NULL, redownloadIn = 1, years = 1991:2017, fireSizeColName = "SIZE_HA", NFDB_pointPath )getFirePoints_NFDB( url = NULL, studyArea = NULL, rasterToMatch = NULL, redownloadIn = 1, years = 1991:2017, fireSizeColName = "SIZE_HA", NFDB_pointPath )
url |
Passed to |
studyArea |
A |
rasterToMatch |
A |
redownloadIn |
Numeric Time in YEARS that we tolerate the data to be "old" i.e. 0.5 would mean "redownload data older than 6 months" |
years |
Numeric vector of consecutive years to fetch. |
fireSizeColName |
Character describing the name of the column containing fire size information. |
NFDB_pointPath |
Passed to |
A sf spatial points object, retaining all columns of the source data
(notably CAUSE, YEAR and SIZE_HA). When rasterToMatch is supplied, an
additional size column gives fire size in pixels.
SpatialPoints from Canadian Fire DatabaseGet Fire SpatialPoints from Canadian Fire Database
getFirePoints_NFDB_V2( url = NULL, studyArea = NULL, redownloadIn = 1, years = 1991:2017, fireSizeColName = "SIZE_HA", NFDB_pointPath = NULL, fun = "sf::st_read", plot = FALSE )getFirePoints_NFDB_V2( url = NULL, studyArea = NULL, redownloadIn = 1, years = 1991:2017, fireSizeColName = "SIZE_HA", NFDB_pointPath = NULL, fun = "sf::st_read", plot = FALSE )
url |
Passed to |
studyArea |
A |
redownloadIn |
Numeric Time in YEARS that we tolerate the data to be "old" i.e. 0.5 would mean "re-download data older than 6 months" |
years |
Numeric vector of consecutive years to fetch. |
fireSizeColName |
Character describing the name of the column containing fire size information. |
NFDB_pointPath |
Passed to |
fun |
Character. The function (as a string, e.g., |
plot |
logical indicating whether to produce plot of fire points. Default FALSE. |
A sf spatial points object (or whatever class fun returns), retaining
all columns of the source data (notably CAUSE, YEAR and SIZE_HA).
Download and prepare fire data from National Fire Database
getFirePolygons(url, years, useInnerCache = FALSE, ...)getFirePolygons(url, years, useInnerCache = FALSE, ...)
url |
Character (or |
years |
years to filter fire polygons by |
useInnerCache |
logical indicating whether to cache the |
... |
additional arguments passed to |
list of fire polygons by year
latestNBACUrl() for the discovery helper used when url is missing.
Mostly this is about 2 things:
remove fires that were so small that they take less than 1 pixel so they are
not in the buff object but are in the cent object.
the centroid cell is in a buffer or otherwise nonburnable cell (e.g., water). For 1) remove these from the centroid data. For 2) this function will search in the neighbourhood for the next closest pixel that has at least 7 available neighbours that can burn. If not, remove these.
Mostly this is about 2 things:
remove fires that were so small that they take less than 1 pixel so they are
not in the buff object but are in the cent object.
the centroid cell is in a buffer or otherwise nonburnable cell (e.g., water). For 1) remove these from the centroid data. For 2) this function will search in the neighbourhood for the next closest pixel that has at least 7 available neighbours that can burn. If not, remove these.
harmonizeBufferAndPoints(cent, buff, ras, idCol = "FIRE_ID") harmonizeBufferAndPoints(cent, buff, ras, idCol = "FIRE_ID")harmonizeBufferAndPoints(cent, buff, ras, idCol = "FIRE_ID") harmonizeBufferAndPoints(cent, buff, ras, idCol = "FIRE_ID")
cent |
List of points as |
buff |
List of |
ras |
The raster that created the |
idCol |
The column name as a character string with the fire ids.
Defaults to |
Outer wrapper on spread fire polygon data munging that does several things:
ensure buffered fires are entirely in studyArea;
ensure every fire has a corresponding ignition point, and vice versa;
ensure these points are flammable.
harmonizeFireData( firePolys, flammableRTM, spreadFirePoints, areaMultiplier, minSize, pointsIDcolumn = "FIRE_ID", cores = 1 )harmonizeFireData( firePolys, flammableRTM, spreadFirePoints, areaMultiplier, minSize, pointsIDcolumn = "FIRE_ID", cores = 1 )
firePolys |
the semi-processed fire polys, with field matching |
flammableRTM |
a |
spreadFirePoints |
the ignition points corresponding to |
areaMultiplier |
Either a scalar that will buffer |
minSize |
an alternative to |
pointsIDcolumn |
the name of the column denoting fire ids in both
|
cores |
Positive integer.Number of CPU cores (threads) to use for parallel operations. |
harmonizeFireData() returnsreproducible::Cache() digests only the called function's own code, so a cached
harmonizeFireData() call keeps returning its old result when a function it calls
changes. Pass this list as that call's .cacheExtra and those functions become part
of the key.
harmonizeFireDataDeps()harmonizeFireDataDeps()
A list of functions, to pass as reproducible::Cache()'s .cacheExtra.
harmonizeFireData(), makeFireSenseLCCDeps()
What the hindcast simulation is compared with: natural-cause ignitions, escapes, area burned and the fire
sizes of year, all inside the ELF core (the buffer is excluded). Ignitions and escapes are
ELFfireCounts() on the core, so they use the fit's definitions: NFDB points with CAUSE in
naturalCauses of any size are ignitions, and those that escapedFires() keeps (larger than a pixel and
at least escapeSizeHa) are escapes. Area burned is the core-clipped area of the fire polygons
(ELFfireOverlay()), given for the natural-cause polygons and for polygons of every cause, because the
simulation ignites natural fires only but the spread model was fitted to polygons of every cause.
hindcastObserved( coreRaster, firePoints, firePolys, year, escapeSizeHa = 50, pixelAreaHa = prod(terra::res(coreRaster))/10000, naturalCauses = c("L", "N"), polyCauseCol = "FIRECAUS", naturalPolyCauses = "Natural" )hindcastObserved( coreRaster, firePoints, firePolys, year, escapeSizeHa = 50, pixelAreaHa = prod(terra::res(coreRaster))/10000, naturalCauses = c("L", "N"), polyCauseCol = "FIRECAUS", naturalPolyCauses = "Natural" )
coreRaster |
|
firePoints |
|
firePolys |
|
year |
The year to describe. |
escapeSizeHa |
Size (ha) a fire must reach to count as escaped. |
pixelAreaHa |
Area of one pixel (ha). Default: the area of a |
naturalCauses |
Values of |
polyCauseCol |
Column of |
naturalPolyCauses |
Values of |
A list. counts is a one-row data.table: year, ignitions, escapes, areaBurnedHa
(natural-cause polygons in the core), areaBurnedHaAllCause, nFires50 and nFires50AllCause
(clipped pieces of at least escapeSizeHa). sizes is a data.table of the clipped pieces, with
cause ("natural" or "allCause") and ha. polys is the SpatVector of the year's natural-cause
polygons (not clipped; NULL without polygons or a cause column), to draw on a map.
The simulated counterpart of hindcastObserved(), for one simulated year: the year's ignitions and
escapes (ignitionsAndEscapes from fireSense_ignitionPredict) and each fire of the year's burn-ID raster
(rstAnnualBurnID from fireSense_burn, one integer per fire), counted or clipped to the ELF core. A fire
that burned only outside the core is not listed. The simulation burns the buffer too, so these sizes are
smaller than burnSummary$areaBurnedHa for fires crossing the core edge.
hindcastSimulated(burnID, coreRaster, ignitions = NULL, escapeSizeHa = 50)hindcastSimulated(burnID, coreRaster, ignitions = NULL, escapeSizeHa = 50)
burnID |
|
coreRaster |
|
ignitions |
|
escapeSizeHa |
Size (ha) at which a fire counts in |
A list. counts is a one-row data.table: ignitions, escapes, areaBurnedHa and nFires50,
the columns of hindcastObserved()'s counts of the same names. sizes has one row per fire in the
core: fire_id and ha.
fireSense_IgnitionFit writes each fit (ignition and escape together) as a row of an rds
file in a Google Drive folder (its ignitionFitGoogleDriveFolder); fireSense_ELFs reads them
for a multi-ELF study area. With ignitionFitFilename = "latest" those modules use these
functions instead of one named file. Parallel to the spread-fit ledger helpers
(spreadFitFilenameFor(), latestSpreadFits()).
latestIgnitionFits() returns, for every polygon, its rows from the most recently modified
ledger file that has it. Files are read newest first; with polygonIDs, reading stops once
all of them are found. A file already in destinationPath with the same MD5 as on Drive is not
downloaded again; one that differs is downloaded again with reproducible::preProcess().
ignitionFitFilenameFor(fireYears) ignitionFitFileTag latestIgnitionFits( cloudFolderID = ignitionFitLedgerFolder(), destinationPath, polygonIDs = NULL )ignitionFitFilenameFor(fireYears) ignitionFitFileTag latestIgnitionFits( cloudFolderID = ignitionFitLedgerFolder(), destinationPath, polygonIDs = NULL )
fireYears |
The fire years the fit used; only the first and last matter. |
cloudFolderID |
The Google Drive folder (url or id) holding the ledger files; default |
destinationPath |
Local folder for the downloaded files. |
polygonIDs |
Optional. The polygons (ELF ids) wanted; |
ignitionFitFileTag marks the files whose fits use the current model: xgboost Poisson
ignition and escape fits (fireSense_IgnitionFit's modelAlgorithm = "xgboost" with objective
count:poisson). The date is the model version. A fit made under a new model needs a new tag,
so the old files drop out of "latest"; files with an older tag, e.g. "_xgboost" (Tweedie
fits), are never read.
ignitionFitFilenameFor(): the file name a fit over fireYears is written to,
e.g. "fireSenseIgnitionParams_1985-2024_xgboostPoisson_20261013.rds".
latestIgnitionFits(): the ledger rows, in the form fireSense_IgnitionFit writes them
(a data.frame with a geometry column), or NULL when no file matches. Attribute
"ignitionFitFiles" names the file each polygon came from.
Creates a standardized name by combining a pre prefix, a normalized
igOrEsc token (case-transformed), and a post suffix.
igOrEscNames( igOrEsc, pre = "fireSense_", post, case = c("lower", "camel", "sentence", "title") )igOrEscNames( igOrEsc, pre = "fireSense_", post, case = c("lower", "camel", "sentence", "title") )
igOrEsc |
|
pre |
|
post |
|
case |
One of |
character(1) constructed as paste0(pre, transformed(igOrEsc), post).
igOrEscNames("ignition", post = "Covariates") igOrEscNames("escape", pre = "fs_", post = "_Formula", case = "camel")igOrEscNames("ignition", post = "Covariates") igOrEscNames("escape", pre = "fs_", post = "_Formula", case = "camel")
Was this covariate rescaled as linear fuel biomass?
isLinearFuelRange(range)isLinearFuelRange(range)
range |
Length-2 numeric: a covariate's entry in |
TRUE when range is fuelLinearRange, i.e. the fit used linear fuel biomass, so
a prediction must apply fuelLogToLinear() to that covariate before rescaling it. FALSE
for a fit made on the log scale, whose covariates must be left as they are.
The single rule for youngAge: an age is young when it is at or below
cutoffForYoungAge (age <= cutoffForYoungAge). NA is never young. Every
place in fireSenseUtils that decides young or not young calls this function, so
fitting and prediction cannot disagree at the cutoff.
isYoungAge(age, cutoffForYoungAge = fireSenseYoungAgeCutoff)isYoungAge(age, cutoffForYoungAge = fireSenseYoungAgeCutoff)
age |
numeric vector of ages (stand age or time since disturbance), in years. |
cutoffForYoungAge |
age at and below which a pixel is young. |
logical vector the length of age; FALSE where age is NA.
Parses the Apache directory listing at base and returns the URL of the
newest file matching NBAC_<startYear>to<endYear>_<YYYYMMDD>_shp.zip,
selected by the YYYYMMDD stamp embedded in the filename. If the listing
cannot be read or no matching file is found, fallback is returned, so
callers can rely on getting some URL back.
latestNBACUrl( base = "https://cwfis.cfs.nrcan.gc.ca/downloads/nbac/", fallback = paste0(base, "NBAC_1972to2025_20260513_shp.zip") )latestNBACUrl( base = "https://cwfis.cfs.nrcan.gc.ca/downloads/nbac/", fallback = paste0(base, "NBAC_1972to2025_20260513_shp.zip") )
base |
Character. Directory listing URL (must be the parent folder that serves the autoindex page). |
fallback |
Character. URL to return when discovery fails. |
A single character URL.
Logistic functions using 2, 3, 4, or 5 parameters; logisticAll dispatches
to one of them based on length(logisticPars).
logistic4p(x, par) logistic5p(x, par) logistic3p(x, par, par1 = 0.1) logistic3pUpper(x, par, par1 = 0.1) logistic2p(x, par, par1 = 0.1, par4 = 0.5) logisticAll(logisticPars, mat, covPars, lowerSpreadProb, link = NULL)logistic4p(x, par) logistic5p(x, par) logistic3p(x, par, par1 = 0.1) logistic3pUpper(x, par, par1 = 0.1) logistic2p(x, par, par1 = 0.1, par4 = 0.5) logisticAll(logisticPars, mat, covPars, lowerSpreadProb, link = NULL)
x |
Numeric vector. Linear predictor (e.g. |
par |
Numeric vector of logistic parameters whose length matches the
variant: 2 for |
par1 |
Numeric scalar. Lower asymptote (replaces |
par4 |
Numeric scalar. Asymmetry factor (replaces |
logisticPars |
Numeric vector of logistic parameters. Unless |
mat |
Numeric matrix of covariate values, one row per observation. |
covPars |
Numeric vector of covariate coefficients (same length as
|
lowerSpreadProb |
Numeric scalar in |
link |
|
The general form is the 5-parameter sigmoid (Richards' curve):
par1 + (par2 - par1) / (1 + (exp(x) / par3)^(-par4))^par5.
The 4-, 3-, and 2-parameter variants successively fix the lower asymptote
(par1), the inflection-point scale (par3 = 1), and the asymmetry
factor (par5 = 0.5) to reduce the parameter count.
logistic3pUpper is logistic3p with Stukel's (1988) generalized-logistic upper tail
applied to the linear predictor: par1 + (par[1] - par1) / (1 + exp(-H(par[2] * x)))^par[3],
where H leaves negative values alone and, for u = par[2] * x >= 0 and a = par[4], is
(exp(a * u) - 1) / a for a > 0, u for a = 0 and -log(1 - a * u) / a for a < 0
(Stukel, T. A. (1988), Generalized logistic models, JASA 83:426-431; as sirt::pgenlogis()).
par[4] changes only how the curve approaches its upper asymptote: negative values slow the
approach, so pixels with a high linear predictor are no longer all pressed against the ceiling;
par[4] = 0 is logistic3p exactly. In logistic3p the approach to the ceiling is set by the
slope par[2] alone – par[3] shapes only the lower end – so this is the one parameter that
changes the upper end independently.
Numeric vector of logistic values; same length as x (or
nrow(mat) for logisticAll).
Logistic parameter names
logisticParamNameslogisticParamNames
A named list of length 4, with "2p", "3p", "4p", "5p" as names representing the 2-parameter etc. logistic curve.
Used for transforming Biomass to the log scale
logMinB(x)logMinB(x)
x |
Any value to be adjusted with log and a minimum B |
The original vector, logged with a minimum.
Fires have key features that are different than "normal" ecological zonations. These include: 1) the property that they spread horizontally across a landscape, regardless of human-mapped ecological areas. 2) Furthermore, even when homogeneous fire regions are mapped, the homogeneousness may be because of fuel changes that occupy the average condition for an ecological area, not necessarily the boundary conditions. 3) Small areas that encompass an area that is only "several times larger than the largest fires" will be too small to capture the potential for multiple very large fires. 4) Furthermore, very large ecological regions may encompass too much variation in fire-fuel-climate relationships that any estimates of fire behaviour will not be accurate across the whole region. 5) No matter what area is chosen to Thus, to estimate fire behaviour across a large region like Canada, we need polygons that are not too small (>> largest fires), not too big (<<), are not constrained by ecological zones defined by vegetation, have buffers.
makeELFs( x, desiredBuffer = 20000, maxArea = 2.4e+11, destinationPath = ".", singleSpatVector = FALSE, useCache = TRUE ) plotELFs( destinationPath = ".", which = NULL, fill = "green", plan = NULL, fewFires = NULL, fewFiresFill = "grey80", mergedFill = "lightblue", arcticFill = "#fdf2d0", ELFs = NULL, labels = c("code", "name", "none"), labelWhich = c("all", "highlighted"), buffers = TRUE, axes = c("m", "longlat", "none"), ... )makeELFs( x, desiredBuffer = 20000, maxArea = 2.4e+11, destinationPath = ".", singleSpatVector = FALSE, useCache = TRUE ) plotELFs( destinationPath = ".", which = NULL, fill = "green", plan = NULL, fewFires = NULL, fewFiresFill = "grey80", mergedFill = "lightblue", arcticFill = "#fdf2d0", ELFs = NULL, labels = c("code", "name", "none"), labelWhich = c("all", "highlighted"), buffers = TRUE, axes = c("m", "longlat", "none"), ... )
x |
A polygon layer ( |
desiredBuffer |
The distance in |
maxArea |
The area in |
destinationPath |
A path where any downloads should be put. |
singleSpatVector |
Logical. If |
useCache |
Logical. If |
which |
Character. ELF names (e.g., |
fill |
The colour used to fill the |
plan |
The merges and skips to show: |
fewFires |
ELF ids to fill as "not enough fires". |
fewFiresFill |
The colour used to fill the |
mergedFill, arcticFill
|
The colours used to fill the merged ELFs (those the plan merges) and the
Arctic ELFs ( |
ELFs |
The list |
labels |
What |
labelWhich |
|
buffers |
If |
axes |
|
... |
Passed to |
With these five points in mind, we define *Ecologically-based Low Fractal-dimensional polygons, "ELFs", that are constrained by large ecological zones (Canadian Ecozones), are "larg-ish", more "blobby" (low fractal dimension) than other ecological zonation in mountains (which tend to follow elevation contours), and are each buffered (default 20km).
A list of length 2, with rasWhole and rasCentered. Each of these
will have the complete list of ELFs. rasWhole is the whole map of Canada
with the individual ELF highlighted, and rasCentered is just the individual ELF
centred and reprojected so its projected parameters are: long0 is the x mid,
and lat0 = ymin and lat1 = ymax of the individual ELF. This will create ELFs
with the least amount of pixel deformation.
Identify each year's individual fires and buffer them accordingly
makeFireIDs( year, fireRaster, flammableRTM, bufferForFireRaster, areaMultiplier, minSize = 5000, verb = 1 )makeFireIDs( year, fireRaster, flammableRTM, bufferForFireRaster, areaMultiplier, minSize = 5000, verb = 1 )
year |
numeric fire year |
fireRaster |
a |
flammableRTM |
a |
bufferForFireRaster |
buffer size used to group discrete patches of burned pixels as belonging to the same fire |
areaMultiplier |
A scalar that will buffer |
minSize |
The absolute minimum size of the buffer & non-buffer together.
This will be imposed after |
verb |
Logical or numeric related to how much verbosity is printed. |
a data.table with fire ID, buffer status, and pixelID
Processes NTEMS Land Cover Classification (LCC) data for a specific year, adjusting non-flammable classes based on a flammability threshold during reprojection to a target raster's resolution and extent.
makeFireSenseLCC( neededYear, to, maskTo = NULL, nonflammableLCC = fireSenseNonflammableLCC, flammabilityThreshold = fireSenseFlammabilityThreshold, writeTo = NULL, overwrite = TRUE, destinationPath, lccSource = getOption("fireSense.lccSource", "SCANFI"), scanfiVersion = fireSenseSCANFIVersion )makeFireSenseLCC( neededYear, to, maskTo = NULL, nonflammableLCC = fireSenseNonflammableLCC, flammabilityThreshold = fireSenseFlammabilityThreshold, writeTo = NULL, overwrite = TRUE, destinationPath, lccSource = getOption("fireSense.lccSource", "SCANFI"), scanfiVersion = fireSenseSCANFIVersion )
neededYear |
Numeric. The specific year required for the NTEMS Land Cover Classification (LCC) data. |
to |
A |
maskTo |
Optional. A |
nonflammableLCC |
Numeric vector. LCC codes representing non-flammable land cover types (e.g., water, rock, urban). Defaults to fireSenseNonflammableLCC. Pixels with these values are initially masked or converted for thresholding. |
flammabilityThreshold |
Numeric. A value between 0 and 1. Target pixels where the proportion of underlying flammable source pixels is below this threshold will be reclassified to 0 (non-flammable) in the output raster. Defaults to 0.1. |
writeTo |
Character string or |
overwrite |
Logical. Overwrite NTEMS FAO and flammable pixels rasters. |
destinationPath |
Character string. Directory path where source NTEMS data
will be downloaded/loaded (via |
lccSource |
|
scanfiVersion |
Character. Only used when |
This function performs several steps:
Downloads and prepares NTEMS LCC data for the specified neededYear using
LandR::prepInputs_NTEMS_LCC_FAO, cropping and masking to the target extent.
Identifies the dominant flammable land cover class within each pixel of
to. This is done by temporarily masking non-flammable classes
(defined in nonflammableLCC) to NA in the source raster and then
reprojecting using the 'mode' method.
Calculates the proportion of flammable cover within each pixel of
to by reprojecting a binary (1=flammable, 0=non-flammable)
version of the source raster using the 'average' method.
Creates the final raster: Pixels where the proportion of flammable cover
(calculated in step 3) is below the flammabilityThreshold are assigned
a value of 0 (representing non-flammable). Otherwise, pixels retain the
dominant flammable LCC code identified in step 2.
A list of two SpatRaster objects:
the processed land cover classification at the resolution, extent,
and CRS of to with values representing either the modal flammable
LCC code or 0 if the pixel is below the flammabilityThreshold, and
the proportion of each pixel that is flammable in the native resolution
## Not run: # Requires terra and potentially LandR installed # Need example to and maskTo objects library(terra) # Create dummy to and maskTo ras <- rast(xmin = 0, xmax = 10, ymin = 0, ymax = 10, res = 1) values(ras) <- 1 crs(ras) <- "EPSG:4326" # Example CRS sa <- ext(ras) |> as.polygons() |> vect() crs(sa) <- crs(ras) # Define a destination path (replace with a real path) destPath <- tempdir() # Run the function (will likely try to download data) # Note: prepInputs_NTEMS_LCC_FAO might require specific setup or data sources # This example might fail if data download/access isn't configured # fireLCC <- makeFireSenseLCC(neededYear = 2011, # Example year # to = ras, # maskTo = sa, # destinationPath = destPath) # plot(fireLCC) ## End(Not run)## Not run: # Requires terra and potentially LandR installed # Need example to and maskTo objects library(terra) # Create dummy to and maskTo ras <- rast(xmin = 0, xmax = 10, ymin = 0, ymax = 10, res = 1) values(ras) <- 1 crs(ras) <- "EPSG:4326" # Example CRS sa <- ext(ras) |> as.polygons() |> vect() crs(sa) <- crs(ras) # Define a destination path (replace with a real path) destPath <- tempdir() # Run the function (will likely try to download data) # Note: prepInputs_NTEMS_LCC_FAO might require specific setup or data sources # This example might fail if data download/access isn't configured # fireLCC <- makeFireSenseLCC(neededYear = 2011, # Example year # to = ras, # maskTo = sa, # destinationPath = destPath) # plot(fireLCC) ## End(Not run)
makeFireSenseLCC() returnsreproducible::Cache() digests only the called function's own code, so a cached
makeFireSenseLCC() call keeps returning its old result when a function it calls changes.
Pass this list as that call's .cacheExtra and those functions become part of the key.
makeFireSenseLCCDeps(lccSource = getOption("fireSense.lccSource", "SCANFI"))makeFireSenseLCCDeps(lccSource = getOption("fireSense.lccSource", "SCANFI"))
lccSource |
|
Ask for the list rather than writing one out: which functions are in the path depends on
lccSource, which is a run-time option, so a hard-coded list is wrong for the other source and
goes stale when the default moves. It already did – fireSense_dataPrepFit pinned
LandR::prepInputs_NTEMS_LCC_FAO() and kept it after the default became SCANFI, leaving every
SCANFI and CWIM change invisible to the cache.
A list of functions, to pass as reproducible::Cache()'s .cacheExtra.
## Not run: Cache(makeFireSenseLCC(neededYear = 2020, to = rtm, destinationPath = dPath), .cacheExtra = makeFireSenseLCCDeps()) ## End(Not run)## Not run: Cache(makeFireSenseLCC(neededYear = 2020, to = rtm, destinationPath = dPath), .cacheExtra = makeFireSenseLCCDeps()) ## End(Not run)
glm that creates separate GLMs for each item in fuelWrapper on glm that creates separate GLMs for each item in fuel
makeGLM(fuel, landscape, form)makeGLM(fuel, landscape, form)
fuel |
vector of tree species or LCC in landscape by which to subset |
landscape |
created by |
form |
the formula to use - as a character |
landcoverDT object to classify and track non-forest land cover classesCreate landcoverDT object to classify and track non-forest land cover classes
makeLandcoverDT(rstLCC, flammableRTM, forestedLCC, nonForestedLCCGroups)makeLandcoverDT(rstLCC, flammableRTM, forestedLCC, nonForestedLCCGroups)
rstLCC |
landcover raster |
flammableRTM |
a |
forestedLCC |
vector of values representing forested landcover classes in |
nonForestedLCCGroups |
a named list of non-forested flammable landcover groups |
a data.table with columns for pixelID and binary presence of landcover
SpatialPointsDataFrame object to a list of data.table objectsMust supply a raster so that points can be converted to the cells on a raster.
It is assumed that the sizeCol is accurate.
If not, it should be recalculated before this function call.
makeLociList( ras, pts, idsCol = "FIRE_ID", dateCol = "YEAR", sizeCol = "POLY_HA", sizeColUnits = "ha", yearPrefix = "year" )makeLociList( ras, pts, idsCol = "FIRE_ID", dateCol = "YEAR", sizeCol = "POLY_HA", sizeColUnits = "ha", yearPrefix = "year" )
ras |
A raster that will be the template for cells (pixel ids) |
pts |
A list of |
idsCol |
Character string identifying column name in |
dateCol |
Character string identifying column name in |
sizeCol |
Character string identifying column name in |
sizeColUnits |
Character string. Either |
yearPrefix |
Character string prefixed to each year when naming the
output list elements (e.g. |
A list of data.table objects, each with 4 columns, "size" (in pixels), "date",
"ids" from idsCol, and "cells", which are the pixel indices of the
pts points.
guarantees mutually exclusive values in a data table
makeMutuallyExclusive(dt, mutuallyExclusiveCols = list(youngAge = c("vegPC")))makeMutuallyExclusive(dt, mutuallyExclusiveCols = list(youngAge = c("vegPC")))
dt |
a data.table with columns that should be mutually exclusive |
mutuallyExclusiveCols |
A named list, where the name of the list element must be a single
covariate column name in |
a data.table with relevant columns made mutually exclusive
cohortData back into a SpatRaster with some extra detailsPut cohortData back into a SpatRaster with some extra details
makeRastersFromCD(class, cohortData, flammableRTM, pixelGroupMap)makeRastersFromCD(class, cohortData, flammableRTM, pixelGroupMap)
class |
|
cohortData |
A |
flammableRTM |
a |
pixelGroupMap |
A |
a SpatRaster with values equal to class biomass (B)
Combines an initial stand age map with disturbance (fire) history to produce a
time-since-disturbance (TSD) raster. Stand age is trusted for most pixels, but
for pixels whose stand age is unreliable (e.g. non-forest land cover) the fire
history is used instead: a recorded recent burn sets the TSD, while the absence
of one marks the pixel as old (cutoffForYoungAge + 1).
makeTSD( year, firePolys = NULL, fireRaster = NULL, standAgeMap, lcc = NULL, cutoffForYoungAge = fireSenseYoungAgeCutoff, pixToUpdate = NULL, flammablePixels = NULL )makeTSD( year, firePolys = NULL, fireRaster = NULL, standAgeMap, lcc = NULL, cutoffForYoungAge = fireSenseYoungAgeCutoff, pixToUpdate = NULL, flammablePixels = NULL )
year |
the year represented by |
firePolys |
list of |
fireRaster |
a |
standAgeMap |
initial stand age map |
lcc |
Optional |
cutoffForYoungAge |
Numeric. Default is 15. This is the age below which the pixel is considered
"young" –> |
pixToUpdate |
Optional integer vector of |
flammablePixels |
Optional integer vector of flammable |
Which pixels to update from fire history, and which pixels are flammable, can be supplied in one of two ways:
directly, via pixToUpdate and flammablePixels (general purpose); or
via lcc, the landcoverDT produced by fireSense_dataPrepFit, from which
both are derived (non-forest pixels are updated, and lcc$pixelID defines the
flammable mask). This is retained for backwards compatibility.
a SpatRaster with values representing time since disturbance
Replaces the members of each merge in ELFmergePlan() by one ELF. Its rasWhole layer is the
cell-by-cell maximum of the members' layers, so a cell that is core in any member is core. A
buffer drawn around the union of cores equals the union of the members' buffers, so the buffer
does not need redrawing. Its rasCentered layer is that map projected onto a Lambert conformal
conic centred on the merged core, as makeELFs() centres each ELF. Its poly rows are rebuilt
from the merged layer the way makeELFs() builds them.
mergeELFs(ELFs, plan)mergeELFs(ELFs, plan)
ELFs |
list with |
plan |
|
ELFs, with each merge's members replaced by the merged ELF.
For each year (or year period) provided, stacks and extracts covariates from
coarse fuel rasters (split into forested vs. non-forested LCC groups) and climate,
at ignition point locations, then merges results across years, filters unusable
pixels, appends lightning summaries, and orders columns. Results are optionally
cached.
mergePreparedCovs( years, fuelCovsCoarse, ignitionFirePoints, nonForestedLCCGroups, ignitionClimateCoarse, lightningMap, digest, useCache = TRUE )mergePreparedCovs( years, fuelCovsCoarse, ignitionFirePoints, nonForestedLCCGroups, ignitionClimateCoarse, lightningMap, digest, useCache = TRUE )
years |
A vector or list of year identifiers passed to
|
fuelCovsCoarse |
A list (possibly nested by year) of named raster-layer
collections (e.g., |
ignitionFirePoints |
Ignition point locations (e.g., |
nonForestedLCCGroups |
A named vector or list whose names identify the LCC
(land-cover) classes considered non-forested. These names are used to split
|
ignitionClimateCoarse |
A list (possibly by year) of coarse climate rasters
(e.g., |
lightningMap |
A named |
digest |
A cache key supplement (character or list) forwarded to
|
useCache |
|
Processing steps:
Calls stackAndExtract() via Map() for each entry in years,
splitting fuelCovsCoarse per year into:
fuel: all layers not in names(nonForestedLCCGroups)
LCC: layers whose names are in names(nonForestedLCCGroups)
Additional MoreArgs include climate = ignitionClimateCoarse and
fires = ignitionFirePoints.
Optionally caches the list of per-year extractions with
reproducible::Cache() (function name tagged as "stackAndExtract").
Combines the list to a single data.table via data.table::rbindlist().
Removes rows for which the sum across all cover-type columns is zero
(computed as rowSums(.SD) over all columns except ignitions,
yearTxt (from fireSenseUtils), cell, and the climate variable
names).
Renames the cell column to pixelID, coerces year to numeric,
and appends lightning columns by indexing terra::values(terra::rast(lightningMap))
with pixelID.
Optionally reorders columns to place pixelID, ignitions,
climate columns (i.e., names(ignitionClimateCoarse)), and youngAgeTxt
(if it exists) first.
Assumptions / Requirements:
fireSenseUtils::stackAndExtract() must accept arguments years, fuel, LCC,
climate, and fires, and return a data.table-like object with at least
cell, ignitions, and year (or yearTxt) columns.
fireSenseUtils::yearTxt is used as a column name to exclude from cover sums;
ensure it exists/aligns with the data produced by stackAndExtract().
youngAgeTxt is referenced when establishing column order but is not
defined in this scope; if unavailable, it is silently omitted.
pixelID is assumed to be a valid row index into lightningMap raster values.
Lightning layer choice: The code appends all layers provided in lightningMap.
If a single best-performing layer is known (e.g., "lightningDays"), subset
lightningMap before calling this function.
Caching: Large raster inputs are excluded from the cache key via
omitArgs = c("fuel", "LCC"); the caller-supplied digest should capture
the salient identity of those omitted objects to avoid cache collisions.
A data.table of ignition covariates with:
pixelID (formerly cell)
ignitions
Climate covariate columns (names derived from ignitionClimateCoarse)
Cover/class covariates retained from stackAndExtract() (filtered to rows with non-zero cover sum)
Lightning-derived columns appended from lightningMap
year coerced to numeric
If pixelID indexes are not aligned with lightningMap cell indices,
appended lightning values will be incorrect; ensure consistent indexing/resolution.
If fireSenseUtils::yearTxt is absent in the returned data, the exclusion in
.SDcols is harmless, but confirm that the intended year column exists for analysis.
If youngAgeTxt is not defined, it will be ignored when reordering columns.
fireSenseUtils::stackAndExtract, reproducible::Cache, data.table::rbindlist, terra::rast, terra::values
## Not run: # Pseudocode, assuming you have compatible inputs prepared: yrs <- list(`2001` = 2001L, `2002` = 2002L) # fuelCovsCoarse[[year]] is a named list or SpatRaster with LCC class names # ignitionClimateCoarse[[year]] is a SpatRaster of climate layers # ignitionFirePoints are point locations (sf/sp/data.frame accepted by stackAndExtract) # lightningMap is a named SpatRaster (e.g., "lightningDays") out <- mergePreparedCovs( years = yrs, fuelCovsCoarse = fuelCovsCoarse, ignitionFirePoints = ignitionFirePoints, nonForestedLCCGroups = c("Shrub", "Grass", "Bare"), ignitionClimateCoarse = ignitionClimateCoarse, lightningMap = lightningMap["lightningDays"], digest = list(seed = 1L, cfg = "v1"), useCache = TRUE ) data.table::str(out) ## End(Not run)## Not run: # Pseudocode, assuming you have compatible inputs prepared: yrs <- list(`2001` = 2001L, `2002` = 2002L) # fuelCovsCoarse[[year]] is a named list or SpatRaster with LCC class names # ignitionClimateCoarse[[year]] is a SpatRaster of climate layers # ignitionFirePoints are point locations (sf/sp/data.frame accepted by stackAndExtract) # lightningMap is a named SpatRaster (e.g., "lightningDays") out <- mergePreparedCovs( years = yrs, fuelCovsCoarse = fuelCovsCoarse, ignitionFirePoints = ignitionFirePoints, nonForestedLCCGroups = c("Shrub", "Grass", "Bare"), ignitionClimateCoarse = ignitionClimateCoarse, lightningMap = lightningMap["lightningDays"], digest = list(seed = 1L, cfg = "v1"), useCache = TRUE ) data.table::str(out) ## End(Not run)
Returns a per-fire buffer target (in pixels) by scaling size so that
small fires get proportionally larger buffers and large fires plateau
at baseMultiplier * size. The result is then clamped from below by
minSize. Used when generating non-burned "control" pixels around
historical fire perimeters.
multiplier(size, minSize = 1000, baseMultiplier = 5)multiplier(size, minSize = 1000, baseMultiplier = 5)
size |
Numeric vector. Fire sizes in pixels. |
minSize |
Numeric scalar. Absolute floor on the returned size; the
buffer (plus burned pixels) is never smaller than this. Default |
baseMultiplier |
Numeric scalar. Asymptotic multiplier for large
fires (as |
Integer vector the same length as size, giving the target
buffered area in pixels for each fire.
doFit and the ledger?Must this run fit, given doFit and the ledger?
mustFit(doFit, hasLedgerFit, polygon = "")mustFit(doFit, hasLedgerFit, polygon = "")
doFit |
|
hasLedgerFit |
logical: does the ledger hold a usable fit for this polygon? Evaluated
lazily, only when |
polygon |
the polygon identifier, for the error message. |
TRUE to fit, FALSE to use the ledger's fit. Stops when doFit is FALSE and the
ledger has no usable fit.
The archive of all fire points, as a shapefile, on the CFS server. The file was NFDB_point.zip;
CFS renamed it NFDB_point_shp.zip (with _txt and large_fires variants beside it), and the old
name returns HTTP 404. The re-download check in getFirePoints_NFDB() and
getFirePoints_NFDB_V2() then could not fetch a newer release, so the last copy on disk (fires to
2024) kept being used.
nfdbPointUrl()nfdbPointUrl()
The URL, a character string.
NULL, to give to Cache(omitArgs =)
An argument added to a cached call changes its key even when it is NULL. Omitting it while it is
NULL keeps the key of a call made before the argument existed, so the cached result is still found.
omitNullArgs(...)omitNullArgs(...)
... |
Named arguments. |
A character vector: the names of those that are NULL.
covPars and logisticPars
DEoptim::DEoptim does not differentiate between the logistic parameters and the covariates.
This splits the vector into the correct components.
The split is based on the number of covariates.
Therefore the number of logistic parameters is deduced from length(pars) - parsModel.
paramsSeparate(par, parsModel)paramsSeparate(par, parsModel)
par |
Numeric vector of all parameters. The covariate parameters must be the second group. |
parsModel |
Integer. The number of covariates. |
list of 2 numeric vectors covPars and logisticPars, representing the
parameters for the covariates and the logistic equation, respectively.
Create plot with subplots showing: a) area burned; b) number of fires; c) mean fire size.
plotBurnSummary( climateScenario, studyAreaName, outputDir, Nreps, years, pixelSize, simFiles )plotBurnSummary( climateScenario, studyAreaName, outputDir, Nreps, years, pixelSize, simFiles )
climateScenario |
character string specifying the name of a CIMP6 climate scenario,
including SSP, formatted as in |
studyAreaName |
character string giving the study area name |
outputDir |
Path specifying the directory to which outputs figures/objects should be saved. |
Nreps |
the number of simulation replicates/run used to produce summary figures.
NOTE: |
years |
integer (length 2). start and end years for comparison. |
pixelSize |
raster pixel (Cell) size |
simFiles |
Optional character vector of simulation output file paths
(e.g. the |
list of file names corresponding to the figures and/or objects written to disk
Plot cumulative burn maps
plotCumulativeBurns( climateScenario, studyAreaName, outputDir, Nreps, years, rasterToMatch, simFiles )plotCumulativeBurns( climateScenario, studyAreaName, outputDir, Nreps, years, rasterToMatch, simFiles )
climateScenario |
character string specifying the name of a CIMP6 climate scenario,
including SSP, formatted as in |
studyAreaName |
character string giving the study area name |
outputDir |
Path specifying the directory to which outputs figures/objects should be saved. |
Nreps |
the number of simulation replicates/run used to produce summary figures.
NOTE: |
years |
integer (length 2). start and end years for comparison. |
rasterToMatch |
A |
simFiles |
Optional character vector of simulation output file paths
(e.g. the |
list of file names corresponding to the figures and/or objects written to disk
a file path corresponding to the images and/or objects written to disk
One panel each for the number of ignitions, escapes, area burned in the core and fires of at least the escape size: the histogram of the simulated rep-years with the observed value as a vertical line. Area burned and fire count have two lines, the natural-cause and the all-cause observed value.
plotHindcastDistributions(reps, observed, title = NULL)plotHindcastDistributions(reps, observed, title = NULL)
reps |
|
observed |
The result of |
title |
Plot title, e.g. the ELF and year. |
A ggplot.
The cumulative burn map of the simulated rep-years divided by their number (the fraction of rep-years each pixel burned), with the outlines of the observed fire polygons drawn over it.
plotHindcastMap( burnMap, nReps, firePolys = NULL, coreRaster = NULL, title = NULL )plotHindcastMap( burnMap, nReps, firePolys = NULL, coreRaster = NULL, title = NULL )
burnMap |
|
nReps |
Number of rep-years the count is over. |
firePolys |
|
coreRaster |
Optional |
title |
Plot title. |
A ggplot.
The empirical cumulative distribution of core-clipped fire sizes (at least minHa), pooled over the
simulated rep-years, with the observed natural-cause and all-cause fire sizes as step lines.
plotHindcastSizes(simSizes, observed, minHa = 50, title = NULL)plotHindcastSizes(simSizes, observed, minHa = 50, title = NULL)
simSizes |
Numeric vector of simulated fire sizes (ha) pooled over rep-years (the |
observed |
The result of |
minHa |
Sizes below this are left out of both sides (default: 50 ha, the escape size). |
title |
Plot title. |
A ggplot.
Plot historic ignitions, escapes, and area burned
plotHistoricFires( climateScenario, studyAreaName, outputDir, pixelSize, firePolys, ignitionPoints, simFiles )plotHistoricFires( climateScenario, studyAreaName, outputDir, pixelSize, firePolys, ignitionPoints, simFiles )
climateScenario |
character string specifying the name of a CIMP6 climate scenario,
including SSP, formatted as in |
studyAreaName |
character string giving the study area name |
outputDir |
Path specifying the directory to which outputs figures/objects should be saved. |
pixelSize |
raster pixel (Cell) size |
firePolys |
A |
ignitionPoints |
A |
simFiles |
Optional character vector of simulation output file paths
(e.g. the |
list of file names corresponding to the figures and/or objects written to disk
Predictions from ignition model
predictIgnition(model, data, rescaleFactor, lambdaRescaleFactor)predictIgnition(model, data, rescaleFactor, lambdaRescaleFactor)
model |
the model used to fit ignition data (must have a |
data |
data for prediction |
rescaleFactor |
spatial rescaling factor when predicted and fitted data are at different scales.
Calculated as: |
lambdaRescaleFactor |
If the data for fitting has been sampled for pseudo-absences, this imposes a new baseline probability of fire occurrences, hence predictions need to be adjusted. If the original fire prob. is (total no. fires)/(total no. fires + total no. absences), and the fire probability imposed by sampling is (total no. fires)/(total no. fires + no. sampled pseudo-absences), to adjust predicted values, one needs to multiply them by (total no. fires + no. sampled pseudo-absences/(total no. fires + total no. absences). |
vector of predicted values.
Creates fuel covariate layers from tabular inputs using
fireSenseUtils:::fireSenseCovariatesCreate(), converts the resulting data
frame into a raster using SpaDES.tools::rastFromDF(), and aggregates the
raster to a coarser spatial resolution with terra::aggregate() using the
mean.
prepare_FuelCovsCoarse(..., rasTemplate, fact)prepare_FuelCovsCoarse(..., rasTemplate, fact)
... |
Arguments forwarded directly to
|
rasTemplate |
A raster-like object (typically |
fact |
|
The function performs the following steps:
Generates a fuel covariate data frame using
fireSenseUtils:::fireSenseCovariatesCreate(...).
Converts the data frame to a raster aligned with rasTemplate via
SpaDES.tools::rastFromDF().
Aggregates the raster to a coarser resolution using
terra::aggregate(fact = fact, fun = mean).
The aggregation is applied across all raster layers (if present), computing the mean of contributing cells.
A terra::SpatRaster containing aggregated fuel covariate layers at the
coarser spatial resolution defined by fact.
The function assumes that the following are available:
fireSenseUtils:::fireSenseCovariatesCreate() (non-exported API),
SpaDES.tools::rastFromDF(),
the terra package.
No input validation is performed on the structure of the data returned by
fireSenseCovariatesCreate().
This function uses a non-exported function from fireSenseUtils via :::,
which may change without notice across package versions.
terra package reference manual: raster aggregation with aggregate().
SpaDES.tools package reference manual: rastFromDF().
fireSenseUtils package source code: fireSenseCovariatesCreate() (internal API).
terra::aggregate(), SpaDES.tools::rastFromDF()
## Not run: fuelCovsCoarse <- prepare_FuelCovsCoarse( fuels = fuelTable, rasTemplate = templateRaster, fact = 4 ) ## End(Not run)## Not run: fuelCovsCoarse <- prepare_FuelCovsCoarse( fuels = fuelTable, rasTemplate = templateRaster, fact = 4 ) ## End(Not run)
youngAge resolved for each fire yearAs prepare_FuelCovsCoarse(), but the covariates are built once with
fireSenseCovariatesCreate(youngAge = FALSE) and then, for each of years,
youngAge is set from youngAgeAtYear() over every pixel (time since disturbance of the data
year aged to that year, reset by all fires since) and fuel, non-forest land cover and treed
wetland are cleared where it is 1, as fireSenseCovariatesCreate(youngAge = TRUE) does for a
single year. Fuel is cleared to logMinB(0), the value fireSenseCovariatesCreate() gives
a pixel without that fuel. Each year is then aggregated with mean, so youngAge becomes the
proportion of young pixels in a coarse cell.
prepare_FuelCovsCoarseByYear( ..., years, dataYear, nonForest_timeSinceDisturbance, firePixelsByYear, cutoffForYoungAge, rasTemplate, fact )prepare_FuelCovsCoarseByYear( ..., years, dataYear, nonForest_timeSinceDisturbance, firePixelsByYear, cutoffForYoungAge, rasTemplate, fact )
... |
Arguments for |
years |
character, fire years ( |
dataYear |
the year |
nonForest_timeSinceDisturbance |
|
firePixelsByYear |
all fires as |
cutoffForYoungAge |
as in |
rasTemplate |
A raster-like object (typically |
fact |
|
a list named by years of SpatRasters, each as prepare_FuelCovsCoarse() returns,
with a youngAge layer.
Aggregates a list of ignition-relevant climate rasters to a coarser spatial
resolution using terra::aggregate() (mean across source cells) and caches
the resulting list with reproducible::Cache(). The cache key is augmented
with a robust digest of the input rasters and a caller-provided upstream
digest.
prepare_ignitionClimate( ignitionClimateList, fact, digest = NULL, useCache = TRUE )prepare_ignitionClimate( ignitionClimateList, fact, digest = NULL, useCache = TRUE )
ignitionClimateList |
A named or unnamed |
fact |
|
digest |
A digest object (e.g., |
useCache |
|
The function:
Computes a robust digest of ignitionClimateList using
.robustDigest() to capture changes in input rasters.
Appends that digest to the user-supplied digest to form a composite
cache key (dig3).
Aggregates each raster via terra::aggregate(fact = fact, fun = mean).
Wraps the aggregated list in reproducible::Cache() with
omitArgs = "x" (to exclude the ephemeral list element passed to
lapply) and .cacheExtra = dig3 to drive cache invalidation from
the composite digest.
All rasters are processed independently via lapply(), preserving list order
and names.
A list of aggregated climate rasters (typically terra::SpatRaster), in
one-to-one correspondence with ignitionClimateList.
Cache invalidation is controlled by .cacheExtra = dig3, which combines:
a robust digest of the input rasters (.robustDigest(ignitionClimateList)), and
the caller-provided digest (e.g., pipeline/module context).
The symbols .robustDigest() and reproducible::Cache() must be available.
No validation is performed on input types. Aggregation is controlled by the fact parameter.
terra package reference manual: aggregate() (spatial raster aggregation).
reproducible package reference manual and vignettes: Cache() and .cacheExtra.
terra::aggregate(), reproducible::Cache()
## Not run: # Example (requires `terra` rasters and `reproducible` cache setup): upstreamDigest <- .robustDigest(list(module = "Fire", version = "1.0.0")) ignitionClimateCoarse <- prepare_ignitionClimate( ignitionClimateList = sim$historicalClimateRasters[ sim$climateVariablesForFire$ignition ], fact = 4, digest = upstreamDigest ) ## End(Not run)## Not run: # Example (requires `terra` rasters and `reproducible` cache setup): upstreamDigest <- .robustDigest(list(module = "Fire", version = "1.0.0")) ignitionClimateCoarse <- prepare_ignitionClimate( ignitionClimateList = sim$historicalClimateRasters[ sim$climateVariablesForFire$ignition ], fact = 4, digest = upstreamDigest ) ## End(Not run)
Downloads, reads, aggregates, and caches multiple lightning-related rasters
(e.g., daily flashes, flash density, positive CG counts) using
reproducible::prepInputs(), terra::aggregate(), and reproducible::Cache().
The function builds a cache key that combines local processing context
(rasterToMatch, igAggFactor, and the lightning reader) with the remote
hashes of the Google Drive files, so cached results are invalidated whenever
either local parameters or upstream files change.
prepare_LightningData(rtm, igAggFactor, dPath)prepare_LightningData(rtm, igAggFactor, dPath)
rtm |
|
igAggFactor |
|
dPath |
Character. Destination path forwarded to
|
Lightning data is given by the authors of https://www.tandfonline.com/doi/full/10.1080/07055900.2020.1845117 It is currently not hosted by the authors. We therefore host it on Google Drive.
The function maintains an internal mapping of Google Drive file IDs for four lightning products:
lightningDays
lightningDensity
positiveCG
positiveCGdensity
For each product, it:
Resolves the Drive ID to a human URL, obtains remote metadata (hash),
Calls reproducible::prepInputs() with a reading function that should
return a raster aligned to sim$rasterToMatch,
Aggregates the raster with terra::aggregate(fact = P(sim)$igAggFactor),
Caches the result with reproducible::Cache() under a product-specific
function label, seeding the cache with both local and remote digests.
A final Cache() call wraps the list of per-product results to further
stabilize caching across the set.
A named list of aggregated lightning rasters (class list of
terra::SpatRaster), with names matching:
c("lightningDays", "lightningDensity", "positiveCG", "positiveCGdensity").
The cache key includes:
The remote hash of each Google Drive resource (so cloud-side updates bust the cache),
The local context digest of rasterToMatch, igAggFactor, and the reader,
via .robustDigest.
This design minimizes recomputation while remaining sensitive to upstream and local changes.
If prepInputs() expects a function for fun, prefer:
fun = function(...) rld(targetFile, to = sim$rasterToMatch)
instead of calling rld(...) immediately.
User-provided function source (this documentation derives from the code you supplied).
Reproducible workflows with the reproducible package and raster handling
with terra as described in their package manuals and vignettes.
reproducible::prepInputs(), reproducible::Cache(), terra::aggregate()
## Not run: out <- prepare_LightningData( rtm = sim$rasterToMatch, igAggFactor = P(sim)$igAggFactor, rld = readLightningData ) out$lightningDensity ## End(Not run)## Not run: out <- prepare_LightningData( rtm = sim$rasterToMatch, igAggFactor = P(sim)$igAggFactor, rld = readLightningData ) out$lightningDensity ## End(Not run)
Wraps rescaleCovariates() to rescale features according to the modeling
algorithm, and optionally caches results based on a robust digest of the
unscaled input data. Returns a list containing the (possibly) rescaled
covariates, the modeling formula (if any), per-variable rescalers (if any),
the x-axis variable name(s), and the digest used for caching.
prepareCovariatesOuter(unscaledData, algorithm, rescaleVars, useCache = TRUE)prepareCovariatesOuter(unscaledData, algorithm, rescaleVars, useCache = TRUE)
unscaledData |
A |
algorithm |
|
rescaleVars |
|
useCache |
|
This function:
Computes a digest of unscaledData (if useCache = TRUE) using an internal
.robustDigest() to form a .cacheExtra key for reproducible::Cache().
Calls rescaleCovariates() with formula = NULL and family = NULL
(non-xgboost code-paths were removed).
Caches the result while omitting the large arguments "covariates" and
"formula" from cache key construction (via omitArgs), relying on the
explicit digest instead.
Expected columns:
ignitions: if present, is preserved through standardization (xgboost path).
escapes: if present, is preserved through standardization (xgboost path).
year or yr: used to infer xvar (see rescaleCovariates()).
A list with elements:
A data.table with rescaled/standardized covariates.
NULL (the non-xgboost formula path is disabled).
Named numeric vector of per-variable 10-based
rescalers (non-xgboost path) or NULL for xgboost / no-rescale.
Character vector indicating which year-like column(s) were found.
The digest used for caching, or NULL if useCache = FALSE.
rescaleCovariates(), reproducible::Cache()
## Not run: library(data.table) dt <- data.table(pixelID = 1:3, year = c(2001L, 2002L, 2003L), ignitions = c(0, 1, 0), x1 = c(0.01, 2.3, 15)) out <- prepareCovariatesOuter(unscaledData = dt, algorithm = "xgb_classifier", rescaleVars = TRUE, useCache = FALSE) str(out) ## End(Not run)## Not run: library(data.table) dt <- data.table(pixelID = 1:3, year = c(2001L, 2002L, 2003L), ignitions = c(0, 1, 0), x1 = c(0.01, 2.3, 15)) out <- prepareCovariatesOuter(unscaledData = dt, algorithm = "xgb_classifier", rescaleVars = TRUE, useCache = FALSE) str(out) ## End(Not run)
Given a template raster (e.g., a flammability map) and a data.table
containing pixel values for one or more land cover classes, this function
reconstructs each class as a raster layer and returns a multi-layer
SpatRaster whose layer names match the class names supplied in lcc.
putBackIntoRaster(lcc, landcoverDT, flammableMap)putBackIntoRaster(lcc, landcoverDT, flammableMap)
lcc |
character vector.
Names of the land cover class columns in |
landcoverDT |
data.table.
A
|
flammableMap |
SpatRaster.
A |
This function:
Creates a working copy of the template raster's values (initialized to 0
on all non-NA cells and keeping original NAs).
For each class name in lcc, it pulls the corresponding vector from
landcoverDT, assigns those values into the
working vector at positions indicated by landcoverDT$pixelID, and then
writes these values back into a fresh terra::rast(flammableMap) layer.
Stacks all layers into a single terra::rast() and sets layer names to
lcc.
Assumptions / requirements
flammableMap is a terra::SpatRaster providing the spatial geometry,
extent, resolution, and NA mask.
landcoverDT is a data.table with a column named pixelID that indexes
cell positions in the template raster's value vector (i.e., values returned
by terra::values(flammableMap, mat = FALSE)). Indices must be valid and
1-based (R-style).
Each element of lcc is the name of a numeric column in landcoverDT.
All layers are created in the same CRS, resolution, and extent as
flammableMap.
Notes
Non-NA cells in the template are initialized to 0 before assignment, so
only positions referenced by pixelID will receive class values; other
non-NA positions remain 0 in each layer.
If you want to preserve existing values outside pixelID, modify the
initialization step accordingly.
A multi-layer terra::SpatRaster where each layer corresponds to one entry
in lcc, with layer names set to lcc.
terra::rast(), terra::values(), terra::setValues()
## Not run: library(terra) library(data.table) # Template raster (5x5 example) r <- rast(nrows = 5, ncols = 5, vals = NA) # Mark some cells as valid (non-NA) values(r) <- rep(NA_real_, ncell(r)) valid_idx <- c(3, 5, 7, 13, 17, 20) tmp_vals <- values(r, mat = FALSE) tmp_vals[valid_idx] <- 0 r <- setValues(r, tmp_vals) # Data table with pixel indices and two classes dt <- data.table( pixelID = valid_idx, Conifer = c(0.6, 0.2, 0.8, 0.1, 0.0, 0.4), Deciduous = c(0.1, 0.3, 0.0, 0.4, 0.5, 0.2) ) # Rebuild layers out <- putBackIntoRaster( lcc = c("Conifer", "Deciduous"), landcoverDT = dt, flammableMap = r ) out names(out) # "Conifer" "Deciduous" plot(out) ## End(Not run)## Not run: library(terra) library(data.table) # Template raster (5x5 example) r <- rast(nrows = 5, ncols = 5, vals = NA) # Mark some cells as valid (non-NA) values(r) <- rep(NA_real_, ncell(r)) valid_idx <- c(3, 5, 7, 13, 17, 20) tmp_vals <- values(r, mat = FALSE) tmp_vals[valid_idx] <- 0 r <- setValues(r, tmp_vals) # Data table with pixel indices and two classes dt <- data.table( pixelID = valid_idx, Conifer = c(0.6, 0.2, 0.8, 0.1, 0.0, 0.4), Deciduous = c(0.1, 0.3, 0.0, 0.4, 0.5, 0.2) ) # Rebuild layers out <- putBackIntoRaster( lcc = c("Conifer", "Deciduous"), landcoverDT = dt, flammableMap = r ) out names(out) # "Conifer" "Deciduous" plot(out) ## End(Not run)
lapply with bufferForFireRaster.
Years are iteratively processed by makeFireID.this is a wrapper to simplify caching of lapply with bufferForFireRaster.
Years are iteratively processed by makeFireID.
rasterFireBufferDT( years, fireRaster, flammableRTM, bufferForFireRaster, areaMultiplier, minSize = 5000, verb = 1, cores = 1, seed = .bufferSeed(years, fireRaster, flammableRTM, bufferForFireRaster, areaMultiplier, minSize) )rasterFireBufferDT( years, fireRaster, flammableRTM, bufferForFireRaster, areaMultiplier, minSize = 5000, verb = 1, cores = 1, seed = .bufferSeed(years, fireRaster, flammableRTM, bufferForFireRaster, areaMultiplier, minSize) )
years |
numeric fire years |
fireRaster |
a |
flammableRTM |
a |
bufferForFireRaster |
buffer size used to group discrete patches of burned pixels as belonging to the same fire |
areaMultiplier |
A scalar that will buffer |
minSize |
The absolute minimum size of the buffer & non-buffer together.
This will be imposed after |
verb |
Logical or numeric related to how much verbosity is printed.
|
cores |
number of processor cores to use |
seed |
integer. Seeds the per-year draws of buffer pixels. The default is derived from the other inputs, so the same inputs give the same buffers in any session, whatever the state of its random number generator, and the session's random stream is left untouched. Supply a value to get a different set of buffers for the same inputs. |
a list of data.tables named by year, with cols ids, buffer, and pixelID
Create a list of annual ignition points based on fire raster
rasterFireSpreadPoints(fireBufferDT, flammableRTM)rasterFireSpreadPoints(fireBufferDT, flammableRTM)
fireBufferDT |
a |
flammableRTM |
@template flammableRTM |
a list of sf point objects
Generate random beta variates between 2 values and a mean
rbetaBetween(n, l, u, m, shape1, shape2 = NULL)rbetaBetween(n, l, u, m, shape1, shape2 = NULL)
n |
number of observations. If |
l |
scalar numeric for the lower bound. |
u |
scalar numeric for the upper bound. |
m |
scalar numeric for the mean. |
shape1 |
non-negative parameter of the Beta distribution. |
shape2 |
If provided, passed to |
Data is not publicly available; it is currently stored in a User Access Controlled location.
Data comes from William Burrows. Please contact him to obtain data.
This function will get the data (which is in a .txt format) and do all the necessary
sequence of calculations to create a SpatRaster.
readLightningData(filename, ...)readLightningData(filename, ...)
filename |
The local filename to read with |
... |
Passed to |
This will return a SpatRaster object with resolution the same as that
supplied by to or projectTo. If no SpatRaster is supplied, it will
default to resolution of 10000 m (10 km x 10 km).
Kochtubajda, B., & Burrows, W. R. (2020). Cloud-to-Ground Lightning in Canada: 20 Years of CLDN Data. Atmosphere-Ocean, 58(5), 316–332. https://doi.org/10.1080/07055900.2020.1845117
## Not run: # The example fetches from a Google Drive folder that requires # `drive_auth()` credentials. R CMD check runs examples # non-interactively where no Drive token is available, so the body # is gated under \dontrun{} to keep docs complete without breaking # checks. if (require(googledrive, quietly = TRUE)) { crsToUse <- paste("+proj=lcc +lat_0=0 +lon_0=-95 +lat_1=49 +lat_2=77", "+x_0=0 +y_0=0 +datum=NAD83 +units=m +no_defs") ras <- terra::rast( terra::ext(-1115000, -376750, 7267000, 7874000), resolution = 250, vals = 1, crs = crsToUse ) ## Google Drive folder: ## <https://drive.google.com/drive/folders/1ftpKKUO8BZcJ9ba4LDWcmF5uQkpRGmku> data <- list( lightningDays = "1jeKJquhVJsesoNk2EPP1QZkttX3Zwp5c", lightningDensity = "12fnhfKtER-JXkl06M4_yZ3GvpZWtQlIr", positiveCG = "1bn6cQ23tvPicFLHn1tz4Z3AqDzJI4r60", positiveCGdensity = "1GNixhXj1Ex1jT0tWXfhmxef-dX3ze1a4" ) lightning <- Map( url = data, f = function(url) { reproducible::prepInputs( url = url, fun = readLightningData(targetFile, to = ras), destinationPath = file.path(tempdir(), "lightning_data") ) } ) } ## End(Not run)## Not run: # The example fetches from a Google Drive folder that requires # `drive_auth()` credentials. R CMD check runs examples # non-interactively where no Drive token is available, so the body # is gated under \dontrun{} to keep docs complete without breaking # checks. if (require(googledrive, quietly = TRUE)) { crsToUse <- paste("+proj=lcc +lat_0=0 +lon_0=-95 +lat_1=49 +lat_2=77", "+x_0=0 +y_0=0 +datum=NAD83 +units=m +no_defs") ras <- terra::rast( terra::ext(-1115000, -376750, 7267000, 7874000), resolution = 250, vals = 1, crs = crsToUse ) ## Google Drive folder: ## <https://drive.google.com/drive/folders/1ftpKKUO8BZcJ9ba4LDWcmF5uQkpRGmku> data <- list( lightningDays = "1jeKJquhVJsesoNk2EPP1QZkttX3Zwp5c", lightningDensity = "12fnhfKtER-JXkl06M4_yZ3GvpZWtQlIr", positiveCG = "1bn6cQ23tvPicFLHn1tz4Z3AqDzJI4r60", positiveCGdensity = "1GNixhXj1Ex1jT0tWXfhmxef-dX3ze1a4" ) lightning <- Map( url = data, f = function(url) { reproducible::prepInputs( url = url, fun = readLightningData(targetFile, to = ras), destinationPath = file.path(tempdir(), "lightning_data") ) } ) } ## End(Not run)
fireBufferedListDT that are outside flammableRTM
Remove buffered fires in fireBufferedListDT that are outside flammableRTM
removeBufferedFiresOutsideRTM(fireBufferedDT, flammableRTM)removeBufferedFiresOutsideRTM(fireBufferedDT, flammableRTM)
fireBufferedDT |
data.table containing indices for buffered annual fires |
flammableRTM |
a |
fireBufferedDT excluding fires with indices (burned or unburned) outside flammableRTM
Applies either order-of-magnitude rescaling to approximately confine features
to the [0, 10] range (non-xgboost) or standardization via base::scale()
(xgboost path). Preserves key response columns when present.
rescaleCovariates(formula, covariates, rescaleVars, modelAlgorithm)rescaleCovariates(formula, covariates, rescaleVars, modelAlgorithm)
formula |
A model formula or |
covariates |
A |
rescaleVars |
|
modelAlgorithm |
|
Year variable inference: If any of c("year", "yr") match column names (case-insensitive),
xvar is set to the intersection. Otherwise, the code references rows (a TODO),
which is undefined here. This appears to be a bug or placeholder and will error
unless rows exists in scope; consider providing a default (e.g., NULL) or removing.
Non-xgboost path:
Excludes pixelID, ignitions, escapes, year, and yearChar from rescaling.
Computes per-variable rescalers <- 10^(floor(log10(abs(max)))) for variables
whose maxima fall outside [0, 10].
Calls rescaleVarsByMagnitude(covariates, ignitionRescalers) (must exist in scope).
xgboost path:
Standardizes numeric columns except yearChar, ignitions, and escapes.
Preserves original ignitions and (if present) escapes columns.
Attaches centering/scaling attributes under attr(covariates, "scaleData").
External references:
Uses ignitionsTxt and escapesTxt to
refer to the expected response column names. If these are not available,
ensure compatible strings are provided (see exported constants below).
A list with elements:
A data.table after rescaling/standardization.
The input formula (often NULL in current usage).
Named numeric vector of per-variable rescalers (non-xgb) or NULL.
Character vector with detected year-like column(s) or (bug) rows.
## Not run: library(data.table) dt <- data.table(ignitions = c(0,1,0), escapes = c(0,0,1), year = 2001:2003, x1 = c(0.05, 12, 100), x2 = c(5, 6, 7)) # XGBoost-like standardization out_xgb <- rescaleCovariates(NULL, dt, rescaleVars = TRUE, modelAlgorithm = "xgb_tree") str(out_xgb) # Non-xgboost magnitude rescaling out_other <- rescaleCovariates(NULL, dt, rescaleVars = TRUE, modelAlgorithm = "glm") str(out_other) ## End(Not run)## Not run: library(data.table) dt <- data.table(ignitions = c(0,1,0), escapes = c(0,0,1), year = 2001:2003, x1 = c(0.05, 12, 100), x2 = c(5, 6, 7)) # XGBoost-like standardization out_xgb <- rescaleCovariates(NULL, dt, rescaleVars = TRUE, modelAlgorithm = "xgb_tree") str(out_xgb) # Non-xgboost magnitude rescaling out_other <- rescaleCovariates(NULL, dt, rescaleVars = TRUE, modelAlgorithm = "glm") str(out_other) ## End(Not run)
rescale function no.2
rescaleKnown2(x, minNew, maxNew, minOrig, maxOrig)rescaleKnown2(x, minNew, maxNew, minOrig, maxOrig)
x |
a vector to be rescaled |
minNew |
the minimum of the new range |
maxNew |
the max of the new range |
minOrig |
the minimum of the original data |
maxOrig |
the maximum of the original data |
the rescaled vector
data.table according to a named vector of rescalersRescale a data.table according to a named vector of rescalers
rescaleVarsByMagnitude(dt, rescalers)rescaleVarsByMagnitude(dt, rescalers)
dt |
a |
rescalers |
a named vector of rescalers |
the data.table with rescaled values
DEoptim evaluates each surviving member only once, so on a noisy objective the values it holds are partly luck: a lucky low draw survives and is reported as "best". Re-scoring the final population several times and ranking by the mean sees through that. In eight FireSense fits (2026-09-17), DEoptim's best member ranked 1st to 6th of 60 by its replicated mean, and the ledger's "5 best" were five copies of that one member.
rescorePopulation(pop, fn, reps = 10L, cl = NULL, seed = 1L, fnArgs = list()) bestByReplicatedMean(pop, scores, n = 5L)rescorePopulation(pop, fn, reps = 10L, cl = NULL, seed = 1L, fnArgs = list()) bestByReplicatedMean(pop, scores, n = 5L)
pop |
A matrix, one parameter set per row, with the parameter names as column names. |
fn |
The objective function; called as |
reps |
Evaluations per member. |
cl |
A cluster from |
seed |
Base seed. |
fnArgs |
Named list of further arguments to |
scores |
The output of |
n |
How many members to return. |
rescorePopulation() evaluates every row of pop reps times; each evaluation has its own seed
(seed + its index), so the result is reproducible. With a cluster the evaluations run on its
workers, which must already hold whatever fn reads from their global environment (as for DEoptim).
rescorePopulation(): a data.table with member (row of pop), rep and value.
bestByReplicatedMean(): a list with params (a data.table, one row per member, best
first), objFunVal (their replicated means), objFunValSD and member (their rows in pop).
Identical rows of pop count once, so the members returned are distinct.
doFit parameter of the FireSense fit modulesfireSense_spreadFit and fireSense_ignitionFit decide whether to fit from one three-valued
parameter, doFit: NA (default) fits only when the ledger has no usable fit for the polygon,
TRUE always fits (replacing a ledger fit), FALSE never fits (use the ledger fit; stop when
there is none). refitExisting and stopIfNoPreRunFit are deprecated aliases: refitExisting = TRUE is doFit = TRUE; stopIfNoPreRunFit = TRUE is doFit = FALSE (stopIfNoPreRunFit = FALSE only allowed a fit, which is what NA does); when both are set refitExisting wins. An
explicit (non-NA) doFit is never overridden by an alias. A module that does not have an
alias leaves it NA.
resolveDoFit( doFit = NA, refitExisting = NA, stopIfNoPreRunFit = NA, module = "the fit module", message = TRUE )resolveDoFit( doFit = NA, refitExisting = NA, stopIfNoPreRunFit = NA, module = "the fit module", message = TRUE )
doFit |
logical, length one: |
refitExisting, stopIfNoPreRunFit
|
the deprecated aliases; |
module |
character; module name used in the deprecation message. |
message |
logical; send the deprecation message when an alias is set (once per call). |
NA, TRUE or FALSE.
DEoptim
Provides a wrapper around DEoptim::DEoptim, setting up the multiple cluster connections. This will only work if ssh keys are preconfigured on all machines (if using multiple machines).
termsInDEoptim() is deprecated: it counted every parameter not in the formula as a "logit" term, so the per-year
random effect yearSpreadSD was reported as a third logistic parameter. runDEoptim() now
names the parameters with names(lower).
runDEoptim( landscape, annualDTx1000, nonAnnualDTx1000, fireBufferedListDT, historicalFires, itermax, initialpop = NULL, NP = NULL, trace, strategy, cores = NULL, paths, libPath = .libPaths()[1], logPath = tempfile(sprintf("runDEoptim_%s_", format(Sys.time(), "%Y-%m-%d_%H%M%S")), fileext = ".log"), doObjFunAssertions = getOption("fireSenseUtils.assertions", TRUE), iterStep = 25, lower, upper, mutuallyExclusive, formulaToFit, objFunCoresInternal, covMinMax = covMinMax, tests = c("SNLL", "adTest"), maxFireSpread, Nreps, thresh = 550, .c = 0.5, DEoptimControl = list(), .verbose, visualizeDEoptim = logPath, .plots = "screen", plotEvery = 25L, .plotSize = list(height = 1600, width = 2000), rep = 1L, runName = "", progressFile = NULL, nCoresNeeded = NULL, rescoreReps = 10L, sizeLik = "kde", sizeLikDf = 5, weighted = TRUE, adWeight = "auto", link = NULL, escapeSizeHa = NULL, jumpTries = 0, jumpMeanDist = 0, yearAreaWeight = 0, areaDistWeight = 0, penaliseRunaways = TRUE, runawayEdgeFrac = fireSenseRunawayEdgeFrac, runawayEdgeMin = fireSenseRunawayEdgeMin, runawayBufferMultiple = NULL, profileReps = 0L, simulateMembers = 0L, penaliseCapHits = NULL, covCentre = NULL ) termsInDEoptim(fireSense_spreadFormula, thresh, numParams)runDEoptim( landscape, annualDTx1000, nonAnnualDTx1000, fireBufferedListDT, historicalFires, itermax, initialpop = NULL, NP = NULL, trace, strategy, cores = NULL, paths, libPath = .libPaths()[1], logPath = tempfile(sprintf("runDEoptim_%s_", format(Sys.time(), "%Y-%m-%d_%H%M%S")), fileext = ".log"), doObjFunAssertions = getOption("fireSenseUtils.assertions", TRUE), iterStep = 25, lower, upper, mutuallyExclusive, formulaToFit, objFunCoresInternal, covMinMax = covMinMax, tests = c("SNLL", "adTest"), maxFireSpread, Nreps, thresh = 550, .c = 0.5, DEoptimControl = list(), .verbose, visualizeDEoptim = logPath, .plots = "screen", plotEvery = 25L, .plotSize = list(height = 1600, width = 2000), rep = 1L, runName = "", progressFile = NULL, nCoresNeeded = NULL, rescoreReps = 10L, sizeLik = "kde", sizeLikDf = 5, weighted = TRUE, adWeight = "auto", link = NULL, escapeSizeHa = NULL, jumpTries = 0, jumpMeanDist = 0, yearAreaWeight = 0, areaDistWeight = 0, penaliseRunaways = TRUE, runawayEdgeFrac = fireSenseRunawayEdgeFrac, runawayEdgeMin = fireSenseRunawayEdgeMin, runawayBufferMultiple = NULL, profileReps = 0L, simulateMembers = 0L, penaliseCapHits = NULL, covCentre = NULL ) termsInDEoptim(fireSense_spreadFormula, thresh, numParams)
landscape |
A |
annualDTx1000 |
A list of data.table objects. Each list element will be from 1
year, and it must be the same length as |
nonAnnualDTx1000 |
A list of data.table objects. Each list element must be named
with a concatenated sequence of names from |
fireBufferedListDT |
A list of data.table objects. It must be same length as
|
historicalFires |
A named list of |
itermax |
Maximum number of iterations for the DEoptim::DEoptim algorithm. Passed to DEoptim::DEoptim.control. |
initialpop |
Optional. A matrix or vector specifying the initial population
for DEoptim::DEoptim. If |
NP |
Optional. The number of population members (individuals) in DEoptim::DEoptim.
If |
trace |
Integer or Logical. Controls the level of tracing information printed by DEoptim::DEoptim during optimization. Passed to DEoptim::DEoptim.control. |
strategy |
Integer |
cores |
A numeric (for running on localhost only) or a character vector of machine names (including possibly "localhost"), where the length of the vector indicates how many cores should be used on that machine. |
paths |
list of paths containing the |
libPath |
A character string indicating an R package library directory. This location must exist on each machine, though the function will make sure it does internally. |
logPath |
A character string indicating what file to write logs to. This
|
doObjFunAssertions |
logical indicating whether to do assertions. |
iterStep |
Integer. Must be less than |
lower |
Numeric vector. Lower bounds for the parameters being optimized. Passed to DEoptim::DEoptim. If named and including |
upper |
Numeric vector. Upper bounds for the parameters being optimized. Passed to DEoptim::DEoptim. |
mutuallyExclusive |
If there are any covariates, e.g,. |
formulaToFit |
Passed to DEoptim::DEoptim |
objFunCoresInternal |
Integer. The number of cores to use for potential
parallelization within a single call to the objective function ( |
covMinMax, tests, maxFireSpread, Nreps, .verbose
|
Passed to |
thresh |
The threshold for accepting fits; e.g., from |
.c |
Numeric in |
DEoptimControl |
Named list of further |
visualizeDEoptim |
Logical. If |
.plots |
Character string. Specifies the plot destination device (e.g., "screen", "png", "pdf").
Passed to internal plotting functions (likely via |
plotEvery |
Integer. Generations between DEoptim progress figures; the final figures are
always drawn. Passed to |
.plotSize |
List specifying plot |
rep |
Integer. An identifier for the replication number of this optimization run. Used in cache tags and plot filenames. Default 1L. |
runName |
Character string used to label this run. Forwarded to
|
progressFile |
Passed to |
nCoresNeeded |
Integer. How many workers to request for the DEoptim cluster. |
rescoreReps |
Integer. After the fit, each member of the final population is evaluated this
many more times (full evaluations, no early stop) and the result is attached to the returned
object as |
sizeLik, sizeLikDf, weighted, adWeight
|
Passed to |
link |
Passed to |
escapeSizeHa |
Passed to |
jumpTries, jumpMeanDist, yearAreaWeight, areaDistWeight
|
Passed to |
penaliseRunaways |
Passed to |
runawayEdgeFrac, runawayEdgeMin
|
Passed to |
runawayBufferMultiple |
Passed to |
profileReps |
Integer. If above 0, |
simulateMembers |
Integer. If above 0, that many best members of the re-score simulate the
observed fires without the size cap ( |
penaliseCapHits |
Deprecated and ignored; use |
covCentre |
Passed to |
fireSense_spreadFormula |
The formula to be submitted to |
numParams |
The number of parameters (TODO: improve description) |
The result of the clusters::DEoptimIterative() call. This is typically a list where
each element contains the DEoptim::DEoptim object state after a block of iterStep iterations.
The final element represents the state after itermax iterations or upon early stopping.
Extracting only the "ELF" module, runs it via SpaDES.core::simInitAndSpades2() and
returns the vector of polygon IDs from spreadFitPreRun, or the ELF maps. The run is not
cached here: the module caches the national ELF list itself, keyed on its ELFversion
parameter alone and shared through the cloud cache, so a run only downloads it.
runELFs( preRunSetupProject, whatOut = c("fittedNamesOnly", "allNames", "maps"), urlELFresults = paste0("https://drive.google.com/file/d/", "1tkC944mPzR9-y-qCMDB5o2cAR_1MoDz4/view?usp=drive_link") )runELFs( preRunSetupProject, whatOut = c("fittedNamesOnly", "allNames", "maps"), urlELFresults = paste0("https://drive.google.com/file/d/", "1tkC944mPzR9-y-qCMDB5o2cAR_1MoDz4/view?usp=drive_link") )
preRunSetupProject |
list. A SpaDES project object prepared for
|
whatOut |
string. One of |
urlELFresults |
Unused and deprecated; kept so existing calls still work. |
The function:
Restricts preRunSetupProject$modules to entries matching "ELFs".
Initializes and runs the simulation with SpaDES.core::simInitAndSpades2().
Returns sim$spreadFitPreRun[[fireSenseUtils::polygonIDTxt]], or the names or maps
chosen by whatOut.
The function expects preRunSetupProject to be a SpaDES project list with at least:
$modules: character vector of module names.
$paths$modulePath: base directory containing module folders.
A vector corresponding to sim$spreadFitPreRun[[fireSenseUtils::polygonIDTxt]].
Currently, no high arctic
ELFs are returned (e.g., Ecoprovinces starting with either 1. or 2.), nor
3.2.1 or 3.2.4, which have no SCANFI species.
Based on the provided code snippet.
## Not run: # Assuming 'prj' is a valid SpaDES project list: # prj <- somePreparationFunction(...) ids <- runELFs(prj) ## End(Not run)## Not run: # Assuming 'prj' is a valid SpaDES project list: # prj <- somePreparationFunction(...) ids <- runELFs(prj) ## End(Not run)
SCANFI v2 land cover for 2020 in Canada LCC class codes, the same map and source as
LandR::prepInputs_SCANFI_LCC_FAO() starts from. The file's name carries its release, so a copy in
destinationPath or getOption("reproducible.inputPaths") is used as it is, with no call to Google
Drive; otherwise it is downloaded.
sizeRuleLandCover(destinationPath)sizeRuleLandCover(destinationPath)
destinationPath |
Directory to download into. |
Character path of the .tif.
With an intercept in the model the covariates are centred (covCentre of .objfunSpreadFit()), so the
coefficients describe variation and the intercept the level. The centre is the mean of each covariate
of the formula, over every pixel-year in annualDTx1000, after the rescaling and the mutual
exclusivity the objective applies and before it centres: the very values it goes on to centre.
spreadCovCentre( annualDTx1000, nonAnnualDTx1000, formulaToFit, covMinMax = NULL, mutuallyExclusive = list(youngAge = c("class", "nf")) )spreadCovCentre( annualDTx1000, nonAnnualDTx1000, formulaToFit, covMinMax = NULL, mutuallyExclusive = list(youngAge = c("class", "nf")) )
annualDTx1000, nonAnnualDTx1000, covMinMax, mutuallyExclusive
|
As in |
formulaToFit |
The spread formula; the intercept is not a covariate and has no centre. |
NULL when the formula has no intercept (nothing is centred), else a named list, one mean per
covariate, to give as covCentre.
The terms of the formula, preceded by spreadInterceptTxt when the formula has an intercept
(~ 1 + a + b; the module formulas are ~ 0 + ... and have none). The intercept is a column of 1s that
spreadProbFromIntegerCovs() adds after rescaling and centring, so it is multiplied by its
coefficient like every covariate, and paramsSeparate(par, length(spreadDesignCols(f))) finds it as
the first covariate coefficient. spreadCovCols() drops it.
spreadDesignCols(formulaToFit) spreadCovCols(colsToUse)spreadDesignCols(formulaToFit) spreadCovCols(colsToUse)
formulaToFit |
The spread formula, a character string or a formula; |
colsToUse |
A character vector from |
A character vector.
spreadCovCols(): colsToUse without the intercept, i.e. the columns that are covariates
(rescaled, centred, and in covMinMax).
Default values for various things
spreadFitAdditionalColNamesspreadFitAdditionalColNames
fireSense_spreadFit writes each fit as a row of an rds file in a Google Drive folder
(its spreadFitGoogleDriveFolder); fireSense_ELFs and fireSense_dataPrepFit read them.
With spreadFitFilename = "latest" those modules use these functions instead of one named file.
latestSpreadFits() returns, for every polygon, its rows from the most recently modified
ledger file that has it. Files are read newest first; with polygonIDs, reading stops once
all of them are found. A file already in destinationPath with the same MD5 as on Drive is not
downloaded again; one that differs is downloaded again with reproducible::preProcess(), into a
temporary folder first.
spreadFitFilenameFor(fireYears) spreadFitFileTag latestSpreadFits( cloudFolderID = spreadFitLedgerFolder(), destinationPath, polygonIDs = NULL )spreadFitFilenameFor(fireYears) spreadFitFileTag latestSpreadFits( cloudFolderID = spreadFitLedgerFolder(), destinationPath, polygonIDs = NULL )
fireYears |
The fire years the fit used; only the first and last matter. |
cloudFolderID |
The Google Drive folder (url or id) holding the ledger files; default |
destinationPath |
Local folder for the downloaded files. |
polygonIDs |
Optional. The polygons (ELF ids) wanted; |
spreadFitFileTag marks the files whose fits use the current model: fuel biomass on the
linear scale (fuelLogToLinear()), escaped fires starting at 50 ha (escapeSizeHa), and the
objective with the annual-area and area-distribution terms. The date (2026-09-25) is when
this model started, i.e. the model version. Files with an older tag ("_linearFuel_esc50":
the same model before it was dated; "_linearFuel": 1-pixel escape; none: log fuel) hold fits of an earlier model, which
fireSense_spreadPredict would apply wrongly, so "latest" never reads them.
A fit made under a new model needs a new tag, so the old files drop out of "latest".
spreadFitFilenameFor(): the file name a fit over fireYears is written to,
e.g. "fireSenseParams_1985-2024_linearFuel_esc50_20260925.rds".
latestSpreadFits(): the ledger rows, in the form fireSense_spreadFit writes them
(a data.frame with a geometry column), or NULL when no file matches. Attribute
"spreadFitFiles" names the file each polygon came from.
A response curve of logit(p) against a covariate cannot show misfit: its points are the model's
own predictions, so they sit on the fitted curve by construction. What can show misfit is the
share of pixels that actually burned against the share that burned in the fit's own simulations,
binned by each covariate.
spreadFitValidationData( par, landscape, annualDTx1000, nonAnnualDTx1000, formulaToFit, historicalFires, fireBufferedListDT, covMinMax = NULL, mutuallyExclusive = list(youngAge = c("class", "nf")), covCentre = NULL, Nreps = 10, lowerSpreadProb = spreadProbFloor, maxFireSpread = spreadProbCeiling, link = NULL, fitYearSpreadSD = NULL, seed = NULL, ... ) plotSpreadFitValidation(d, nBins = 10L, covariates = NULL, title = NULL) plotSpreadFitResponse(d, covariates = NULL, bins = 40L, title = NULL)spreadFitValidationData( par, landscape, annualDTx1000, nonAnnualDTx1000, formulaToFit, historicalFires, fireBufferedListDT, covMinMax = NULL, mutuallyExclusive = list(youngAge = c("class", "nf")), covCentre = NULL, Nreps = 10, lowerSpreadProb = spreadProbFloor, maxFireSpread = spreadProbCeiling, link = NULL, fitYearSpreadSD = NULL, seed = NULL, ... ) plotSpreadFitValidation(d, nBins = 10L, covariates = NULL, title = NULL) plotSpreadFitResponse(d, covariates = NULL, bins = 40L, title = NULL)
par |
The fitted parameters, as given to |
landscape |
A |
annualDTx1000 |
A list of data.table class objects. Each list element is
data from a single calendar year, and whose name takes the form |
nonAnnualDTx1000 |
Like |
formulaToFit |
Formula, put provided as a character string, not class |
historicalFires |
A named list of |
fireBufferedListDT |
A named list of |
covMinMax |
This is a 2 row by multiple column data.frame indicating the minimum and maximum values of the original covariate data values. These will be used to rescale the covariates internally so that they are all between 0 and 1. It is important to not simply rescale internally here because only 1 year is run at a time; all years must be rescaled for a given covariate by the same amount. |
mutuallyExclusive |
Named list of vectors describing groups of model
terms that must not be active together (mutually exclusive in the
formula). Default |
covCentre |
Optional named list or vector of values subtracted from the rescaled covariates
of the same name. |
Nreps |
Simulations per fire; use the fit's |
lowerSpreadProb |
Numeric. Lower bound for |
maxFireSpread |
A value for |
link |
Passed to |
fitYearSpreadSD |
If |
seed |
If not |
... |
Further arguments to |
d |
The output of |
nBins |
Number of quantile bins per covariate. |
covariates |
The covariates to plot; all of the formula's by default. |
title |
Plot title; a default is used when |
bins |
Number of hexagons (or squares, without hexbin) across each panel. |
spreadFitValidationData() runs the objective's simulations for the fitted parameters,
recording which pixels burned (.objfunSpreadFit(returnBurned = TRUE)), and returns one row per
spreadable pixel-year in the buffers of the fitted fires.
plotSpreadFitValidation() plots, per covariate, the observed and the simulated burned share
by quantile bin of that covariate.
plotSpreadFitResponse() plots the fitted response curves (the model, not the data).
Both plot functions take the data as their first argument and return a ggplot, so they can be
given to SpaDES.core::Plots() as fn.
spreadFitValidationData(): a data.table, one row per spreadable pixel-year inside
the buffers of the fires the objective fits (minFireSize, escapeSizeHa): year (the name
of the fire year), pixelID, observed (1 if the pixel is inside an observed fire, else 0),
simulated (the share of the Nreps simulations in which it burned), p (its fitted spread
probability, without the per-year random effect), and one column per covariate of the formula
with its raw value (the stored integer / 1000, before rescaling and mutual exclusivity).
attr(, "spreadFitValidation") holds what the plots need: the parameters, covMinMax,
covCentre, lowerSpreadProb, link, Nreps, the names of the covariates and of the
annual (climate) ones, and yearsNotSimulated – years the objective declined to simulate,
which have no rows.
plotSpreadFitValidation(): a ggplot, one panel per covariate. Pixel-years are binned
by quantiles of the covariate: all of them for climate covariates, only those where it is
present (above its covMinMax minimum, else above 0) for the others, and one bin per value
for covariates with two values or fewer. Each bin shows the observed burned share and the
mean simulated burned share, at the bin's mean covariate value, with its number of
pixel-years along the bottom.
plotSpreadFitResponse(): a ggplot, one panel per covariate with more than two values.
The line is logit(p) the fitted parameters give a "pure stand": that covariate alone, every
other covariate absent (0 after rescaling: other fuels, youngAge, non-forest), and climate at
its median. Behind it, the pixel-years' own predicted logit(p) (only where the covariate is
present, except for climate), up to its 99.5th percentile. Those follow the curve by
construction: the figure shows the model's response, not how well it fits.
runDEoptim() sets options(clusters.workerMemoryGB) to this, unless the user has set it, so
clusters (>= 0.0.75) caps workers per host by free memory from a fit's first cluster build.
Measured 2026-10-09 over 457 spread-fit workers on 15 hosts: peak resident memory median 4.5 GB,
90th percentile about 6.5 GB, maximum 14.1 GB. Once a fit has run a chunk, its own record is used.
spreadFitWorkerMemoryGBspreadFitWorkerMemoryGB
The covariates that are 0 or 1: youngAge, the non-forest land-cover groups (nfLCC_*) and the
species-mode treedWetland indicator (not the biomass treedWetland_agb). Their range is always
c(0, 1) (spreadIndicatorRanges()), not the range of the data: in an ELF where one is constant
the data's range is zero wide and rescaling divides by zero.
spreadIndicatorCols(covNames) spreadIndicatorRanges(covNames)spreadIndicatorCols(covNames) spreadIndicatorRanges(covNames)
covNames |
character vector of covariate column names. |
spreadIndicatorCols(): the names among covNames that are indicators.
spreadIndicatorRanges(): a named list, c(0, 1) for each of them.
One value each, used wherever the spread model needs them. spreadProbCeiling is the upper bound
fireSense_spreadFit gives maxAsymptote, and the default maxFireSpread of the objective, the
gates and the validation: a fitted maxAsymptote above it draws a warning. How a year's random
effect can take a pixel past it is described at maxFireSpread in .objfunSpreadFit().
spreadProbFloor is the default lowerSpreadProb, the link's lower asymptote, in the objective, the
gates, the validation and fireSense_spreadPredict.
spreadProbCeiling spreadProbFloorspreadProbCeiling spreadProbFloor
Numeric scalars.
x1000 integer to usable by spreadConvert covariates from their x1000 integer to usable by spread
spreadProbFromIntegerCovs( shortAnnDTx1000 = NULL, annDTx1000, nonAnnualDTx1000, indexNonAnnual, yr, covMinMax = NULL, mutuallyExclusive, colsToUse, doAssertions, logisticPars, covPars, maxFireSpread, lowerSpreadProb, covCentre = NULL )spreadProbFromIntegerCovs( shortAnnDTx1000 = NULL, annDTx1000, nonAnnualDTx1000, indexNonAnnual, yr, covMinMax = NULL, mutuallyExclusive, colsToUse, doAssertions, logisticPars, covPars, maxFireSpread, lowerSpreadProb, covCentre = NULL )
shortAnnDTx1000 |
Optional if annDTx1000 and nonAnnualDTx1000 are supplied. Otherwise it must be a data.frame/data.table that has all covariates (>= 1 forests, >=0 non-forests, climate, youngAge), whose values are 1000x their original values so they can be stored as integers. |
annDTx1000 |
TODO: use description of |
nonAnnualDTx1000 |
If |
indexNonAnnual |
|
yr |
A single character or numeric/integer representing the full year (e.g., 2020) to
but used. This year will be extracted from both the |
covMinMax |
A data.table, one column for each column in |
mutuallyExclusive |
If there are any covariates, e.g,. |
colsToUse |
Optional. If this is supplied, it must be a character vector indicating
the column names to use in |
doAssertions |
Logical. If |
logisticPars |
Numeric vector of logistic parameters. Unless |
covPars |
Numeric vector of covariate coefficients (same length as
|
maxFireSpread |
A value for |
lowerSpreadProb |
Numeric. Lower bound for |
covCentre |
Optional named list or vector: |
This returns the full data.table to be used for fireSense, on the original numeric
i.e., real scale, with the x1000 reversed.
Computes each parameter set's spreadProb on the covariates of the first block (the two years with
the most burned area) exactly as .objfunSpreadFit() does, and applies spreadProbGateTest(),
which the objective itself calls, without simulating any fire. A parameter set that fails is one
the objective would bail on in the first block. It is cheap enough to screen thousands of draws.
spreadProbGates( par, annualDTx1000, nonAnnualDTx1000, historicalFires, formulaToFit, covMinMax = NULL, mutuallyExclusive = list(youngAge = c("class", "nf")), covCentre = NULL, link = NULL, maxFireSpread = spreadProbCeiling, lowerSpreadProb = spreadProbFloor, lanscape1stQuantileThresh = 0.265, minFireSize = 2, escapeSizeHa = NULL, landscape = NULL, years = NULL, doAssertions = FALSE )spreadProbGates( par, annualDTx1000, nonAnnualDTx1000, historicalFires, formulaToFit, covMinMax = NULL, mutuallyExclusive = list(youngAge = c("class", "nf")), covCentre = NULL, link = NULL, maxFireSpread = spreadProbCeiling, lowerSpreadProb = spreadProbFloor, lanscape1stQuantileThresh = 0.265, minFireSize = 2, escapeSizeHa = NULL, landscape = NULL, years = NULL, doAssertions = FALSE )
par |
a named numeric vector as |
annualDTx1000, nonAnnualDTx1000, historicalFires, covMinMax, mutuallyExclusive, covCentre, link, maxFireSpread, lowerSpreadProb, lanscape1stQuantileThresh, minFireSize, escapeSizeHa, landscape
|
As in |
formulaToFit |
character; the spread formula, as in the objective. |
years |
character; the years to test. Default: the objective's first block. |
doAssertions |
logical; as in the objective. |
for one par, a list of logicals pass (every tested year passes), burny and notSpread
(any tested year fails that check), medianOK (every year's median is in range) and the tested
years; for a list of parameter sets, a data.frame with one row of the same per set.
.objfunSpreadFit() refuses to simulate a year (it scores the minLik floor, and the parameter set
is "bailed") unless its spreadProb passes these checks. The objective calls this function, so the
checks cannot differ from spreadProbGates().
spreadProbGateTest( spreadProb, ceiling, lowerSpreadProb, maxFireSpread, lanscape1stQuantileThresh )spreadProbGateTest( spreadProb, ceiling, lowerSpreadProb, maxFireSpread, lanscape1stQuantileThresh )
spreadProb |
numeric; the spreadProb of each pixel of the year. |
ceiling |
numeric; the logistic's asymptote (its first parameter). Pixels at or above 99% of
it (or within 2.5% of |
lowerSpreadProb, maxFireSpread
|
numeric; the median must be within them. |
lanscape1stQuantileThresh |
numeric; the first quartile of the non-edge values must be below this. |
a list: pass; burny (first quartile too high, "Too burny a landscape"); notSpread
((q90 - q10) / median <= 0.025, "Not spread out enough"); medianOK; and the nonEdgeValues and
their summary that the objective logs.
Prepare covariate table with ignition year, fuel class, climate value, and land cover
stackAndExtract(years, fuel, LCC, climate, fires = NULL)stackAndExtract(years, fuel, LCC, climate, fires = NULL)
years |
character vector of fire years with FS notation e.g. |
fuel |
raster brick of aggregated fuel classes, or a list of them named by |
LCC |
raster brick of aggregated LCC classes, or a list named by |
climate |
list of raster layers named by climate variable
with raster layer names matching |
fires |
list of spatial points representing annual ignitions |
a data.frame with cell numbers, ignitions, and covariates for each year
This simply converts to integers times 1000 so that the values can be saved more quickly to disk, for example.
toX1000(lst, omitCols = "pixelID")toX1000(lst, omitCols = "pixelID")
lst |
a data.frame of (at least some) numeric columns |
omitCols |
character A vector of column names to not convert |
The same data.frame, but with columns converted to integer and times 1000
Update name of layers in a climate raster stack
updateStackYearNames(annualDataStack, desiredYears)updateStackYearNames(annualDataStack, desiredYears)
annualDataStack |
|
desiredYears |
character |
DEoptim object pars
Make histograms of DEoptim object pars
visualizeDE(DE, cachePath, titles, lower, upper)visualizeDE(DE, cachePath, titles, lower, upper)
DE |
An object from a DEoptim::DEoptim call |
cachePath |
A |
titles |
titles of plots |
lower |
lower limit on x axis |
upper |
upper limit on x axis |
youngAge of pixels at one fire yearTime since disturbance at year is the smaller of the data year's time since disturbance
aged to year (tsd + (year - dataYear)) and the years since the last fire before year
(year - fireYear), taken over all fires in firePixelsByYear, not only the fires being
fitted. A pixel is young when that is at or below cutoffForYoungAge. A pixel with NA
time since disturbance (non-flammable or unknown) is never young, whether or not a fire covers
it. A fire in year itself does not count: fire years are compared with the state before
they burn.
youngAgeAtYear( tsd, dataYear, year, firePixelsByYear = list(), cutoffForYoungAge = fireSenseYoungAgeCutoff, pixelID = tsd$pixelID )youngAgeAtYear( tsd, dataYear, year, firePixelsByYear = list(), cutoffForYoungAge = fireSenseYoungAgeCutoff, pixelID = tsd$pixelID )
tsd |
|
dataYear |
the year |
year |
the fire year. |
firePixelsByYear |
list named by fire year ( |
cutoffForYoungAge |
Numeric. Default is 15. This is the age below which the pixel is considered
"young" –> |
pixelID |
integer, the pixels to return, in this order. Default: all rows of |
It works on pixel IDs, so the same call serves the buffered pixels of a spread fit and every
pixel of the landscape (ignition, validation). Only fires in
(year - cutoffForYoungAge):(year - 1) can make a pixel young, so only those are read.
integer vector, 1 for young and 0 otherwise, one per pixelID.
youngAge is mutually exclusive withyoungAge is mutually exclusive with every other non-climate spread covariate: wherever it is
non-zero, fuel biomass, non-forest land cover (always named nfLCC_*, see fuelClassPrep())
and treedWetland are all zero. fireSense_spreadFit derives this from the covariates it holds
apart from climate (its non-annual covariate table); fireSense_spreadPredict has no such
table, so it identifies fuel columns itself (their covMinMax range) and calls this for the
rest, so both modules end up applying the identical rule.
youngAgeExclusiveCols(covNames, fuelCols = character())youngAgeExclusiveCols(covNames, fuelCols = character())
covNames |
character vector of all covariate column names present (excluding |
fuelCols |
character vector, the fuel biomass column names among |
a named list, list(youngAge = <matched column names>), suitable as
makeMutuallyExclusive()'s mutuallyExclusiveCols argument.