diff --git a/.github/workflows/pkgdown-module.yaml b/.github/workflows/pkgdown-module.yaml new file mode 100644 index 0000000..35a93e9 --- /dev/null +++ b/.github/workflows/pkgdown-module.yaml @@ -0,0 +1,30 @@ +## Thin caller: build this module's pkgdown site and publish it with GitHub Pages. +## The job lives in PredictiveEcology/actions, so its setup and pins move once: +## https://github.com/PredictiveEcology/actions/blob/main/.github/workflows/pkgdown-module.yaml +## Background: PredictiveEcology/SpaDES-modules#40. +## +## Publishes from `development` (the pilot's choice; which branch should publish +## is an open question on #40). Pull requests build the site without deploying. +## The site is at https://predictiveecology.github.io/fireSense_ignitionPredict/ until a +## custom domain is set with the `url` input. + +name: pkgdown-module + +on: + push: + branches: [development] + pull_request: + branches: [development] + workflow_dispatch: + +jobs: + pkgdown-module: + ## The called workflow's deploy job pushes to gh-pages. A called workflow can + ## only reduce what the caller grants, never widen it, so the write scope has + ## to be granted here. + permissions: + contents: write + uses: PredictiveEcology/actions/.github/workflows/pkgdown-module.yaml@main + with: + module: fireSense_ignitionPredict + diff --git a/.github/workflows/render-module-rmd.yaml b/.github/workflows/render-module-rmd.yaml index 88a3af9..44100fb 100644 --- a/.github/workflows/render-module-rmd.yaml +++ b/.github/workflows/render-module-rmd.yaml @@ -20,8 +20,8 @@ on: - development paths: - .github/workflows/render-module-rmd.yaml - - fireSense_IgnitionPredict.Rmd - - fireSense_IgnitionPredict.R + - fireSense_ignitionPredict.Rmd + - fireSense_ignitionPredict.R workflow_dispatch: jobs: @@ -35,4 +35,4 @@ jobs: contents: write uses: PredictiveEcology/actions/.github/workflows/render-module-rmd.yaml@main with: - module: fireSense_IgnitionPredict + module: fireSense_ignitionPredict diff --git a/.github/workflows/testthat-module.yaml b/.github/workflows/testthat-module.yaml index 0ef537b..e7dda1c 100644 --- a/.github/workflows/testthat-module.yaml +++ b/.github/workflows/testthat-module.yaml @@ -1,5 +1,5 @@ ## Example caller for the testthat-module reusable workflow. -## Replace fireSense_IgnitionPredict with the module name (which must match the repository name). +## Replace fireSense_ignitionPredict with the module name (which must match the repository name). name: testthat-module @@ -10,7 +10,7 @@ on: branches: [main, master, development] paths: - .github/workflows/testthat-module.yaml - - fireSense_IgnitionPredict.R + - fireSense_ignitionPredict.R - R/** - tests/** workflow_dispatch: @@ -22,4 +22,4 @@ jobs: ## itself is all it needs. uses: PredictiveEcology/actions/.github/workflows/testthat-module.yaml@main with: - module: fireSense_IgnitionPredict + module: fireSense_ignitionPredict diff --git a/.gitignore b/.gitignore index 5d5f4db..2b23413 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,5 @@ .DS_Store .quarto -fireSense_IgnitionPredict_cache/ -fireSense_IgnitionPredict2.Rmd +fireSense_ignitionPredict_cache/ +fireSense_ignitionPredict2.Rmd diff --git a/NEWS.md b/NEWS.md index 6c2d9bc..0b325c5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,37 @@ +# fireSense_ignitionPredict 1.2.0 + +This release fixes two errors that changed how many fires the module predicted. Weather and landscape conditions are now compared against the conditions the model was fitted on; before, each year was compared only with itself, so every year looked average to the model and hot or dry years did not stand out. And when several fires started in the same area, the module could count more escaped fires than actually escaped; each escape is now counted once. Results will differ from earlier versions, and should be more realistic. + +The module also has a new name, `fireSense_ignitionPredict` (lower-case "i"), so projects need to update the name they use for it. It can now use a separate fitted model for each region (ELF) of a study area, runs faster on large maps, and has automated tests and a documentation website. + +- The coarse-to-fine cell mapping of the ignition raster is computed once and kept in `mod`, then applied each year by indexing, instead of regridding the raster to `flammableRTM` with `postProcess()` every year (about 3 s a year at 6.7M fine cells). It is rebuilt if the extent, dimensions or crs of `ignitionFitRTM` or `flammableRTM` change. Ignitions and escapes are unchanged. + +# fireSense_ignitionPredict 1.1.1 + +- reqdPkgs now lists `data.table` and `reproducible`, which the module calls (`:=`, `copy`, `set`, `setnames`, `rbindlist`, `as.data.table`, `postProcess`) but did not list. Version 1.1.1. + +# fireSense_ignitionPredict 1.1.0 + +- Renamed from `fireSense_IgnitionPredict` to `fireSense_ignitionPredict` (module naming convention `_`); projects must rename the module and its `params` key. The class `fireSense_IgnitionFit` and the objects `fireSense_IgnitionFitted`, `fireSense_IgnitionFittedList` and `fireSense_IgnitionPredicted` keep their names. Version 1.1.0. + +- `ignitionsAndEscapes` gains `escaped`: whether each ignition escaped, with exactly `escapes` of a coarse + pixel's ignitions TRUE. `escapes` is the coarse pixel's count, repeated on each of its ignitions, and fireSense + spread `escapes` fires from every one of them, so a coarse pixel with 4 ignitions and 2 escapes gave 8 escaped + fires instead of 2. Version 1.0.0.9003. + +- New parameter `.studyAreaName` (default `NA`), the name PredictiveEcology modules use for the study area. This module does not use it yet. +- Several fitted ELFs in one study area: with `fireSense_IgnitionFittedList` and `fireSense_EscapeFittedList` (one fit per ELF, named by `ELFind`) and `rasterToMatchLargeELF`, each ELF's models predict the coarse pixels of that ELF, with its own `scaleData`. The Poisson and binomial draws are still made once over all pixels, so one ELF gives exactly the previous result. + +# fireSense_IgnitionPredict (development version) + +## Bug fixes + +- Covariates are now standardized with the center and scale stored by the fit (`fireSense_IgnitionFitted$scaleData`, `fireSense_EscapeFitted$scaleData`). They were standardized with each year's own mean and sd, so every year looked average to the models. With `rescaleVars = TRUE`, a fitted object without `scaleData` is now an error. + +## Cleanup + +- The `save` event now does nothing and says so. It used to fail, because it wrote `sim$fireSense_IgnitionPredicted`, which the module no longer creates. `IgnitionPredictSave()` is removed. + # fireSense_IgnitionPredict 1.0.0 First release from `development` since `master` was last updated (2021-03-11). Full history: https://github.com/PredictiveEcology/fireSense_IgnitionPredict/compare/5a242fa...v1.0.0 diff --git a/README.md b/README.md index 922a00c..121ae5a 120000 --- a/README.md +++ b/README.md @@ -1 +1 @@ -fireSense_IgnitionPredict.md \ No newline at end of file +fireSense_ignitionPredict.md \ No newline at end of file diff --git a/citation.bib b/citation.bib index 1441840..6f71453 100644 --- a/citation.bib +++ b/citation.bib @@ -1,6 +1,6 @@ @Manual{, - title = {fireSense_IgnitionPredict}, + title = {fireSense_ignitionPredict}, author = {{Authors}}, organization = {Organization}, address = {Somewhere, Someplace}, diff --git a/citations/references_fireSense_IgnitionPredict.bib b/citations/references_fireSense_ignitionPredict.bib similarity index 100% rename from citations/references_fireSense_IgnitionPredict.bib rename to citations/references_fireSense_ignitionPredict.bib diff --git a/fireSense_IgnitionPredict.R b/fireSense_IgnitionPredict.R deleted file mode 100644 index eeffa25..0000000 --- a/fireSense_IgnitionPredict.R +++ /dev/null @@ -1,309 +0,0 @@ -defineModule(sim, list( - name = "fireSense_IgnitionPredict", - description = "Predict rates of fire frequency from a model fitted using the - fireSense_IgnitionFit module. These can be used to feed the - ignition component of a landscape fire model (e.g fireSense).", - keywords = c("fire frequency", "additive property", "poisson", "negative binomial", "fireSense"), - authors = c( - person("Eliot", "McIntire", email = "eliot.mcintire@nrcan-rncan.gc.ca", role = c("aut", "cre")), - person("Ian", "Eddy", email = "ian.eddy@nrcan-rncan.gc.ca", role = "aut"), - person("Jean", "Marchal", email = "jean.d.marchal@gmail.com", role = "aut"), - person("Alex M", "Chubaty", email = "achubaty@for-cast.ca", role = "ctb") - ), - childModules = character(), - version = list(SpaDES.core = "0.1.0", fireSense_IgnitionPredict = "1.0.0"), - timeframe = as.POSIXlt(c(NA, NA)), - timeunit = "year", - citation = list("citation.bib"), - documentation = list("README.txt", "fireSense_IgnitionPredict.Rmd"), - reqdPkgs = list( - "magrittr", "terra", - "PredictiveEcology/fireSenseUtils@development (>=0.1.0)" - ), - loadOrder = list(after = "fireSense_dataPrepPredict"), - parameters = bindrows( - # Eliot removed this Jan 2026; why not put this in the `reqdPkgs`? And also, it is not used anymore. - # defineParameter("ignitionFit_Predict_Package", "character", "glmmTMB", NA, NA, - # desc = paste( - # "The package used to fit the ignitionFit model.", - # "It wil be loaded using Require." - # ) - # ), - defineParameter("modelAlgorithm", "character", "xgboost", NA, NA, - "Can be `xgboost`, `glmmtmb`, `glm.nb`, `glmmadaptive`, `glm`; only `xgboost` is supported currently"), - defineParameter("rescaleVars", "logical", default = TRUE, - desc = paste("Attempt to rescale variables? If `rescalers` is defined,", - "use it to rescale variables as `var / rescalers['var']`. ", - "Otherwise, `scale()` will be used to rescale variables to `[0,1]`,", - "if they are not already within this range.")), - defineParameter(".runInitialTime", "numeric", start(sim), NA, NA, - desc = "when to start this module? By default, the start - time of the simulation." - ), - defineParameter(".runInterval", "numeric", 1, NA, NA, - desc = paste("optional. Interval between two runs of this module"), - ("expressed in units of simulation time. By default, 1 year.") - ), - defineParameter(".saveInitialTime", "numeric", NA, NA, NA, - desc = "optional. When to start saving output to a file." - ), - defineParameter(".saveInterval", "numeric", NA, NA, NA, - desc = "optional. Interval between save events." - ), - defineParameter(".useCache", "logical", FALSE, NA, NA, - desc = paste( - "Should this entire module be run with caching activated?", - "This is generally intended for data-type modules,", - "where stochasticity and time are not relevant" - ) - ) - ), - inputObjects = bindrows( - expectsInput("fireSense_EscapeFitted", "fireSense_EscapeFit", - desc = "An object of class `fireSense_EscapeFit` created with the `fireSense_IgnitionFit` module.", - sourceURL = NA - ), - expectsInput("fireSense_IgnitionFitted", "fireSense_IgnitionFit", - desc = "An object of class `fireSense_IgnitionFit` created with the `fireSense_IgnitionFit` module.", - sourceURL = NA - ), - expectsInput("fireSense_igAndEscapePred_Covariates", "data.table", - desc = paste( - "A `data.table` with prediction variables and a", - "column named 'pixelID'" - ) - ), - expectsInput("flammableRTM", "SpatRaster", - sourceURL = NA, - desc = "RTM without ice/rocks/urban/water. Flammable map with 0 and 1." - ), - ), - outputObjects = bindrows( - createsOutput("fireSense_IgAndEscapeProbRas", "SpatRaster", - desc = "a raster layer of the annual ignition and escape probabilities" - ), - createsOutput( - "ignitionsAndEscapes", "data.table", - paste("A data.table containing pixelID (referencing flammableRTM),", - "ignitions, escapes, and their associated probabilities") - ) - ) -)) - -doEvent.fireSense_IgnitionPredict <- function(sim, eventTime, eventType, debug = FALSE) { - moduleName <- currentModule(sim) - - switch(eventType, - init = { - # Require(P(sim)$ignitionFit_Predict_Package) - - sim <- scheduleEvent(sim, eventTime = P(sim)$.runInitialTime, moduleName, "run") - - if (!is.na(P(sim)$.saveInitialTime)) { - sim <- scheduleEvent(sim, P(sim)$.saveInitialTime, moduleName, "save", .last()) - } - }, - run = { - sim <- IgnitionPredictRun(sim) - if (!is.na(P(sim)$.runInterval)) { - sim <- scheduleEvent(sim, time(sim) + P(sim)$.runInterval, moduleName, "run") - } - }, - save = { - sim <- IgnitionPredictSave(sim) - - if (!is.na(P(sim)$.saveInterval)) { - sim <- scheduleEvent(sim, time(sim) + P(sim)$.saveInterval, moduleName, "save", .last()) - } - }, - warning(paste("Undefined event type: '", current(sim)[1, "eventType", with = FALSE], - "' in module '", current(sim)[1, "moduleName", with = FALSE], "'", - sep = "" - )) - ) - return(invisible(sim)) -} - -IgnitionPredictRun <- function(sim) { - ## checks - if (is.null(sim$fireSense_IgnitionFitted$lambdaRescaleFactor)) { - sim$fireSense_IgnitionFitted$lambdaRescaleFactor <- 1 - } - - igCov <- copy(sim$fireSense_igAndEscapePred_Covariates) - - igCov <- na.omit(igCov) - - modelAlgorithm <- paramCheckOtherMods(sim, "modelAlgorithm") - rescaleVars <- paramCheckOtherMods(sim, "rescaleVars") - data <- prepareCovariatesOuter(igCov, - algorithm = modelAlgorithm, - rescaleVars = rescaleVars, useCache = FALSE) - pixelId <- igCov$pixelID - igCov <- data$covariates - set(igCov, NULL, "pixelID", pixelId) - - - # scaleData <- sim$fireSense_IgnitionFitted$scaleData - # if (!is.null(scaleData)) { - # vars <- unlist(scaleData$dimnames) - # vars <- setdiff(vars, c("pixelID", "year")) - # - # - # browser() - # # these rescalings are possibly because the rescales are on the raw species, - # # but the fuel classes may have been merged - # intersect(vars, names(igCov)) - # for (v in vars) { - # set(igCov, NULL, v, - # scaleAgain(igCov[[v]], - # scaleData$`scaled:center`[[v]], - # scaleData$`scaled:scale`[[v]])) - # } - # } - # if (!is.null(sim$fireSense_IgnitionFitted$rescales)) { - # igCov <- rescaleVarsByMagnitude( - # igCov, - # sim$fireSense_IgnitionFitted$rescales - # ) - # } - - # From here, it makes predictions from each KFold, then averages them to get the probabilities for - # each cell; same for Escape, which is conditional on having ignited. - modsHere <- sim$fireSense_IgnitionFitted$modelList$model - modsOnly <- modsHere[grep("Fold", names(modsHere))] - if (!is.null(modsOnly)) { - predsIgnList <- Map(model = modsOnly, function(model) { - predict(model, newdata = igCov) - }) - - predsIgnsMat <- do.call(cbind, predsIgnList)# |> sort() |> unname() - predsIgns <- rowMeans(predsIgnsMat) - igns <- rpois(NROW(predsIgns), lambda = predsIgns) # can't use rtweedie because don't know the dispersion parameter - - modsEscHere <- sim$fireSense_EscapeFitted$modelList$model - modsEscOnly <- modsEscHere[grep("Fold", names(modsEscHere))] - whHasIgns <- which(igns > 0) - - predsEscList <- Map(model = modsEscOnly, - function(model) { - predsEsc <- predict(model, newdata = igCov[whHasIgns]) - pmax(pmin(1, predsEsc), 0) # the escape model is tweedie, so can go above 1, below 0 rarely - }) - predsEscsMat <- do.call(cbind, predsEscList)# |> sort() |> unname() - predsEscs <- rowMeans(predsEscsMat) - escs <- rbinom(NROW(predsEscs), size = igns[whHasIgns], prob = predsEscs) - - set(igCov, NULL, c("igProb", "ignitions"), list(predsIgns, igns)) - set(igCov, whHasIgns, c("escapeProb", "escapes"), list(predsEscs, escs)) - - igDisAggFactor <- ceiling(sim$fireSense_IgnitionFitted$modelList$fittingRes / c(res(sim$flammableRTM)[1])) - } else { - stop("Not tested anymore") - # TODO: I think fireSenseUtils::predictIgnition is now redundant - # TODO: let a user pass a package:fun to prdict, like LandR.CS, else this? - igCov[, igProb := predict(sim$fireSense_IgnitionFitted$model, - newdata = igCov, - se.fit = FALSE, - re.form = NA, type = "response" - )] - # TODO: this is 1 in all applications except Ceres' (which predate the new model) - igCov[, igProb := igProb * sim$fireSense_IgnitionFitted$lambdaRescaleFactor] - - ignitionFamily <- params(sim)$fireSense_IgnitionFit$ignitionFamily[[1]] |> format() - - possTypes <- data.table(family = c("poisson", "nbinom"), generator = c("rpois", "rnbinom")) - generator <- possTypes[family %in% ignitionFamily]$generator - generator <- eval(parse(text = generator)) - - igCov[, ignitions := generator( - n = length(igProb), - lambda = igProb - )] - - # Escape - igCov[, escapeProb := predict(sim$fireSense_EscapeFitted$model, - newdata = igCov, - se.fit = FALSE, - re.form = NA, type = "response" - )] - - igCov[, escapes := rbinom(n = .N, size = ignitions, prob = escapeProb)] - - igDisAggFactor <- ceiling(sim$fireSense_IgnitionFitted$fittingRes / c(res(sim$flammableRTM)[1])) - } - # Ignite - accounting for spatial resolution of models - - # disaggregate the coarse raster to size of flammableRTM - # draw ignitions/escapes from smaller pixel size - igRas <- rast(sim$ignitionFitRTM) - igRas[igCov$pixelID] <- igCov$pixelID - - # can't use disagg because it may not be round pixels - # igRas <- disagg(igRas, fact = igDisAggFactor) - igRas <- postProcess(igRas, to = sim$flammableRTM, method = "near") - igRas[sim$flammableRTM[] != 1] <- NA - - igRasDT <- as.data.table(igRas, cells = TRUE) - setnames(igRasDT, new = c("pixelID", "chunkyPixels")) - # igs <- igCov[igRasDT, on = c("pixelID" = "chunkyPixels")] - # nomatch = NULL --> removes pixels that aren't in igCov, which are non flammable - igs <- igRasDT[igCov, on = c("chunkyPixels" = "pixelID"), nomatch = NULL] - # igs <- igRasDT[igCov, on = c("chunkyPixels" = "pixelID")] - # randomly sample - # use unique because of multiple pixelID per chunkyPixel - drawTable <- unique(igs[ignitions > 0, .(chunkyPixels, ignitions, escapes)]) - pixelID_igs <- lapply(drawTable$chunkyPixels, - FUN = function(n, draw = drawTable, ig = igs) { - sampledChunk <- draw[chunkyPixels == n] - pixelID_pop <- igs[chunkyPixels == sampledChunk$chunkyPixels] - drawn <- sample(pixelID_pop$pixelID, size = sampledChunk$ignitions) - igPixels <- try(ig[pixelID %in% drawn, .(pixelID, igProb, ignitions, escapeProb, escapes)]) - if (is(igPixels, "try-error")) browser() - return(igPixels) - } - ) |> - rbindlist() #will this fail with zero ignitions? - - #for posterior analysis - igProbRas <- rast(sim$ignitionFitRTM) - igProbRas[igCov$pixelID] <- igCov$igProb - escapeProbRas <- igProbRas - escapeProbRas[igCov$pixelID] <- igCov$escapeProb - sim$fireSense_IgAndEscapeProbRas <- c(igProbRas, escapeProbRas) - names(sim$fireSense_IgAndEscapeProbRas) <- c("ignitionProb", "escapeProb") - - if (!is.na(P(sim)$.saveInterval)) { - #TODO: implement proper plotting control - Plots(igProbRas, types = Par$.plots, filename = paste0("IgnitionProbability_yr", time(sim))) - } - randomOrder <- sample(1:nrow(pixelID_igs)) - sim$ignitionsAndEscapes <- pixelID_igs[randomOrder,] #Randomize order - - return(invisible(sim)) -} - -IgnitionPredictSave <- function(sim) { - timeUnit <- timeunit(sim) - currentTime <- time(sim, timeUnit) - - writeRaster( - sim$fireSense_IgnitionPredicted, - filename = file.path(paths(sim)$out, paste0("fireSense_IgnitionPredicted_", timeUnit, currentTime, ".tif")) - ) - - return(invisible(sim)) -} - -.inputObjects <- function(sim) { - # cacheTags <- c(currentModule(sim), "otherFunctions:.inputObjects") - # dPath <- asPath(inputPath(sim), 1) - # message(currentModule(sim), ": using dataPath '", dPath, "'.") - - return(invisible(sim)) -} - - -scaleAgain <- function(v, center, scale) { - (v - center)/ scale -} diff --git a/fireSense_IgnitionPredict.Rmd b/fireSense_IgnitionPredict.Rmd deleted file mode 100644 index cb8775d..0000000 --- a/fireSense_IgnitionPredict.Rmd +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: "fireSense_IgnitionPredict Manual" -subtitle: "v.`r SpaDES.core::moduleMetadata(module = 'fireSense_IgnitionPredict', path = '..')$version`" -date: "Last updated: `r Sys.Date()`" -output: - bookdown::html_document2: - toc: true - toc_float: true - theme: sandstone - number_sections: false - df_print: paged - keep_md: yes -editor_options: - chunk_output_type: console -bibliography: citations/references_fireSense_IgnitionPredict.bib -link-citations: true -always_allow_html: true ---- - -# fireSense_IgnitionPredict Module - - -(ref:fireSense-IgnitionPredict) *fireSense_IgnitionPredict* - -```{r setup-fireSense-IgnitionPredict, include=FALSE} -knitr::opts_chunk$set(echo = TRUE, eval = FALSE, results = "hold") ## change to eval = TRUE if all chunks are to be evaluated - -dir.create("figures", showWarnings = FALSE) - -download.file(url = "https://img.shields.io/badge/Made%20with-Markdown-1f425f.png", - destfile = "figures/markdownBadge.png", - mode = "wb") -``` - -[![made-with-Markdown](figures/markdownBadge.png)](https://commonmark.org) - - - -#### Authors: - -`r paste(as.character(SpaDES.core::moduleMetadata(module = "fireSense_IgnitionPredict", path = '..')$authors), sep = ', ')` - - -## Module Overview - -### Module summary - -Predicts fire frequency or rates of fire counts using a model fitted with the `fireSense_IgnitionFit` module. -Use them to feed the ignition component of a landscape fire model (e.g fireSense [@Marchal:2017a; @Marchal:2017b; @Marchal:2019]). - -### Module inputs and parameters - -Table \@ref(tab:moduleInputs-fireSense-IgnitionPredict) shows the full list of module inputs. - -```{r moduleInputs-fireSense-IgnitionPredict, echo = FALSE, eval = TRUE, message = FALSE, warning = FALSE} -df_inputs <- SpaDES.core::moduleInputs("fireSense_IgnitionPredict", "..") -knitr::kable(df_inputs, - caption = "List of (ref:fireSense-IgnitionPredict) input objects and their description.") |> - kableExtra::kable_styling(latex_options = "scale_down", full_width = TRUE) -``` - -Summary of user-visible parameters (Table \@ref(tab:moduleParams-fireSense-IgnitionPredict)) - - -```{r moduleParams-fireSense-IgnitionPredict, echo = FALSE, eval = TRUE, message = FALSE, warning = FALSE} -df_params <- SpaDES.core::moduleParams("fireSense_IgnitionPredict", "..") -knitr::kable(df_params, caption = "List of (ref:fireSense-IgnitionPredict) parameters and their description.") |> - kableExtra::kable_styling(latex_options = "scale_down", full_width = TRUE) -``` - -### Events - -- Module initialization; -- Make predictions; - -### Plotting - -Write what is plotted. - -### Saving - -Write what is saved. - -### Module outputs - -Description of the module outputs (Table \@ref(tab:moduleOutputs-fireSense-IgnitionPredict)). - -```{r moduleOutputs-fireSense-IgnitionPredict, echo = FALSE, eval = TRUE, message = FALSE, warning = FALSE} -df_outputs <- SpaDES.core::moduleOutputs("fireSense_IgnitionPredict", "..") -knitr::kable(df_outputs, caption = "List of (ref:fireSense-IgnitionPredict) outputs and their description.") |> - kableExtra::kable_styling(latex_options = "scale_down", full_width = TRUE) -``` - -### Links to other modules - - -Predictions made with this module can be used to feed the ignition component of a landscape fire model (e.g fireSense). - -### Getting help - -- - -## References - - diff --git a/fireSense_IgnitionPredict.md b/fireSense_IgnitionPredict.md deleted file mode 100644 index c693046..0000000 --- a/fireSense_IgnitionPredict.md +++ /dev/null @@ -1,196 +0,0 @@ ---- -title: "fireSense_IgnitionPredict Manual" -subtitle: "v.0.2.0" -date: "Last updated: 2025-04-08" -output: - bookdown::html_document2: - toc: true - toc_float: true - theme: sandstone - number_sections: false - df_print: paged - keep_md: yes -editor_options: - chunk_output_type: console -bibliography: citations/references_fireSense_IgnitionPredict.bib -link-citations: true -always_allow_html: true ---- - -# fireSense_IgnitionPredict Module - - -(ref:fireSense-IgnitionPredict) *fireSense_IgnitionPredict* - - - -[![made-with-Markdown](figures/markdownBadge.png)](https://commonmark.org) - - - -#### Authors: - -Jean Marchal [aut], Eliot McIntire [aut], Ian Eddy [aut, cre], Alex M Chubaty [ctb] - - -## Module Overview - -### Module summary - -Predicts fire frequency or rates of fire counts using a model fitted with the `fireSense_IgnitionFit` module. -Use them to feed the ignition component of a landscape fire model (e.g fireSense [@Marchal:2017a; @Marchal:2017b; @Marchal:2019]). - -### Module inputs and parameters - -Table \@ref(tab:moduleInputs-fireSense-IgnitionPredict) shows the full list of module inputs. - - - - - - - - - - - - - - - - - - - -
(\#tab:moduleInputs-fireSense-IgnitionPredict)(\#tab:moduleInputs-fireSense-IgnitionPredict)List of (ref:fireSense-IgnitionPredict) input objects and their description.
objectName objectClass desc sourceURL
NA NA NA NA
- -Summary of user-visible parameters (Table \@ref(tab:moduleParams-fireSense-IgnitionPredict)) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(\#tab:moduleParams-fireSense-IgnitionPredict)(\#tab:moduleParams-fireSense-IgnitionPredict)List of (ref:fireSense-IgnitionPredict) parameters and their description.
paramName paramClass default min max paramDesc
.plots character screen NA NA Used by Plots function, which can be optionally used here
.plotInitialTime numeric 0 NA NA Describes the simulation time at which the first plot event should occur.
.plotInterval numeric NA NA NA Describes the simulation time interval between plot events.
.saveInitialTime numeric NA NA NA Describes the simulation time at which the first save event should occur.
.saveInterval numeric NA NA NA This describes the simulation time interval between save events.
.studyAreaName character NA NA NA Human-readable name for the study area used - e.g., a hash of the studyarea obtained using `reproducible::studyAreaName()`
.seed list NA NA Named list of seeds to use for each event (names).
.useCache logical FALSE NA NA Should caching of events or module be used?
- -### Events - -- Module initialization; -- Make predictions; - -### Plotting - -Write what is plotted. - -### Saving - -Write what is saved. - -### Module outputs - -Description of the module outputs (Table \@ref(tab:moduleOutputs-fireSense-IgnitionPredict)). - - - - - - - - - - - - - - - - - -
(\#tab:moduleOutputs-fireSense-IgnitionPredict)(\#tab:moduleOutputs-fireSense-IgnitionPredict)List of (ref:fireSense-IgnitionPredict) outputs and their description.
objectName objectClass desc
NA NA NA
- -### Links to other modules - - -Predictions made with this module can be used to feed the ignition component of a landscape fire model (e.g fireSense). - -### Getting help - -- - -## References - - diff --git a/fireSense_ignitionPredict.R b/fireSense_ignitionPredict.R new file mode 100644 index 0000000..92c1509 --- /dev/null +++ b/fireSense_ignitionPredict.R @@ -0,0 +1,343 @@ +defineModule(sim, list( + name = "fireSense_ignitionPredict", + description = paste( + "Predicts annual ignition and escape probabilities from the models fitted by", + "fireSense_ignitionFit and fireSense_EscapeFit, and draws the pixels that ignite and escape."), + keywords = c("fire frequency", "additive property", "poisson", "negative binomial", "fireSense"), + authors = c( + person("Eliot", "McIntire", email = "eliot.mcintire@nrcan-rncan.gc.ca", role = c("aut", "cre")), + person("Ian", "Eddy", email = "ian.eddy@nrcan-rncan.gc.ca", role = "aut"), + person("Jean", "Marchal", email = "jean.d.marchal@gmail.com", role = "aut"), + person("Alex M", "Chubaty", email = "achubaty@for-cast.ca", role = "ctb") + ), + childModules = character(), + version = list(SpaDES.core = "0.1.0", fireSense_ignitionPredict = "1.2.0"), + timeframe = as.POSIXlt(c(NA, NA)), + timeunit = "year", + citation = list("citation.bib"), + documentation = list("README.txt", "fireSense_ignitionPredict.Rmd"), + reqdPkgs = list( + "data.table", "magrittr", "terra", + "PredictiveEcology/reproducible@development", + "PredictiveEcology/fireSenseUtils@development (>=0.1.0)" + ), + loadOrder = list(after = "fireSense_dataPrepPredict"), + parameters = bindrows( + defineParameter("modelAlgorithm", "character", "xgboost", NA, NA, + paste("Algorithm used to fit the models; only `xgboost` is supported.", + "Must agree with the value in the other fireSense modules.")), + defineParameter("rescaleVars", "logical", default = TRUE, + desc = paste("Rescale the covariates before predicting? With `xgboost` they are standardized", + "with `scale()`. Must agree with the value in the other fireSense modules.")), + defineParameter(".runInitialTime", "numeric", start(sim), NA, NA, + desc = "Time of the first prediction." + ), + defineParameter(".runInterval", "numeric", 1, NA, NA, + desc = "Interval between predictions, in years. `NA` predicts once." + ), + defineParameter(".saveInitialTime", "numeric", NA, NA, NA, + desc = "Time of the `save` event, which does nothing. `NA` means never." + ), + defineParameter(".saveInterval", "numeric", NA, NA, NA, + desc = "If not `NA`, the ignition probability raster is plotted each year." + ), + defineParameter(".studyAreaName", "character", NA, NA, NA, + "Human-readable name for the study area used."), + defineParameter(".useCache", "logical", FALSE, NA, NA, + desc = paste( + "Should this entire module be run with caching activated?", + "This is generally intended for data-type modules,", + "where stochasticity and time are not relevant" + ) + ) + ), + inputObjects = bindrows( + expectsInput("fireSense_EscapeFitted", "fireSense_EscapeFit", + desc = "Fitted escape models (`$modelList$model`, one per fold), from `fireSense_EscapeFit`.", + sourceURL = NA + ), + expectsInput("fireSense_IgnitionFittedList", "list", + desc = paste("Only with several fitted ELFs: one `fireSense_IgnitionFitted` per ELF, named by `ELFind`.", + "Each ELF's model predicts the coarse pixels of that ELF.")), + expectsInput("fireSense_EscapeFittedList", "list", + desc = "Only with several fitted ELFs: one `fireSense_EscapeFitted` per ELF, named as `fireSense_IgnitionFittedList`."), + expectsInput("rasterToMatchLargeELF", "SpatRaster", + desc = "Only with several fitted ELFs: each pixel's ELF (`ELFind`), from `fireSense_ELFs` with a `studyAreaLarge`."), + expectsInput("fireSense_IgnitionFitted", "fireSense_IgnitionFit", + desc = paste("Fitted ignition models (`$modelList$model`, one per fold) and `$modelList$fittingRes`,", + "from `fireSense_ignitionFit`."), + sourceURL = NA + ), + expectsInput("fireSense_igAndEscapePred_Covariates", "data.table", + desc = paste( + "This year's covariates, from `fireSense_dataPrepPredict`.", + "`pixelID` is the cell index of `ignitionFitRTM`." + ) + ), + expectsInput("flammableRTM", "SpatRaster", + sourceURL = NA, + desc = "Binary raster, 1 where the pixel is flammable." + ), + ), + outputObjects = bindrows( + createsOutput("fireSense_IgAndEscapeProbRas", "SpatRaster", + desc = paste("Two layers, `ignitionProb` (expected ignitions per pixel) and `escapeProb`,", + "at the resolution of `ignitionFitRTM`.") + ), + createsOutput( + "ignitionsAndEscapes", "data.table", + paste("One row per ignited pixel, in random order: `pixelID` (cell index of `flammableRTM`),", + "`igProb`, `ignitions`, `escapeProb`, `escapes` of the coarse pixel it was drawn from, and", + "`escaped`, whether this ignition escaped: exactly `escapes` of a coarse pixel's rows are TRUE.") + ) + ) +)) + +#' Event dispatcher +#' +#' Events: `init`, `run` (predict, repeated every `.runInterval`), `save` (does nothing). +#' +#' @param sim A `simList`. +#' @param eventTime Time of the event. +#' @param eventType Name of the event. +#' @param debug Not used. +#' +#' @return The `simList`, invisibly. +doEvent.fireSense_ignitionPredict <- function(sim, eventTime, eventType, debug = FALSE) { + moduleName <- currentModule(sim) + + switch(eventType, + init = { + sim <- scheduleEvent(sim, eventTime = P(sim)$.runInitialTime, moduleName, "run") + + if (!is.na(P(sim)$.saveInitialTime)) { + sim <- scheduleEvent(sim, P(sim)$.saveInitialTime, moduleName, "save", .last()) + } + }, + run = { + sim <- IgnitionPredictRun(sim) + if (!is.na(P(sim)$.runInterval)) { + sim <- scheduleEvent(sim, time(sim) + P(sim)$.runInterval, moduleName, "run") + } + }, + save = { + message("fireSense_ignitionPredict: the `save` event does nothing.") + }, + warning(paste("Undefined event type: '", current(sim)[1, "eventType", with = FALSE], + "' in module '", current(sim)[1, "moduleName", with = FALSE], "'", + sep = "" + )) + ) + return(invisible(sim)) +} + +#' Predict and draw this year's ignitions and escapes +#' +#' Averages the per-fold predictions of the ignition models, draws ignitions per coarse pixel +#' (Poisson), then does the same for escapes (binomial, given ignition). Each ignition is placed in +#' a random flammable `flammableRTM` pixel inside its coarse pixel. +#' +#' @param sim A `simList`. +#' +#' @return The `simList`, invisibly, with `fireSense_IgAndEscapeProbRas` and `ignitionsAndEscapes`. +IgnitionPredictRun <- function(sim) { + igCov <- copy(sim$fireSense_igAndEscapePred_Covariates) + + igCov <- na.omit(igCov) + + paramCheckOtherMods(sim, "modelAlgorithm") + rescaleVars <- paramCheckOtherMods(sim, "rescaleVars") + # The models were fitted on covariates standardized once, over all fitting years; a year's + # own mean and sd would make every year look average. + ## The fitted models: one ignition and one escape fit, or one of each per fitted ELF (named by ELF), each + ## applied to the coarse pixels of its own ELF (sim$rasterToMatchLargeELF). The Poisson and binomial draws + ## are made once over all pixels, as before, so one ELF gives exactly the old result. + fits <- ignitionFitsByELF(sim, igCov$pixelID) + + # From here, it makes predictions from each KFold, then averages them to get the probabilities for + # each cell; same for Escape, which is conditional on having ignited. + predsIgns <- rep(NA_real_, NROW(igCov)) + for (f in fits) { + covsHere <- igCov[f$rows] + # The models were fitted on covariates standardized once, over all fitting years; a year's + # own mean and sd would make every year look average. + if (rescaleVars) covsHere <- scaleAsFit(covsHere, f$ign$scaleData, "fireSense_IgnitionFitted") + predsIgns[f$rows] <- foldMeanPrediction(f$ign, covsHere) + } + igns <- rpois(NROW(predsIgns), lambda = predsIgns) # can't use rtweedie because don't know the dispersion parameter + + whHasIgns <- which(igns > 0) + predsEscs <- rep(NA_real_, NROW(igCov)) + for (f in fits) { + rowsEsc <- intersect(whHasIgns, f$rows) + covsHere <- igCov[rowsEsc] + if (rescaleVars) covsHere <- scaleAsFit(covsHere, f$esc$scaleData, "fireSense_EscapeFitted") + # the escape model is tweedie, so can go above 1, below 0 rarely + predsEscs[rowsEsc] <- foldMeanPrediction(f$esc, covsHere, clamp01 = TRUE) + } + predsEscs <- predsEscs[whHasIgns] + escs <- rbinom(NROW(predsEscs), size = igns[whHasIgns], prob = predsEscs) + + set(igCov, NULL, c("igProb", "ignitions"), list(predsIgns, igns)) + set(igCov, whHasIgns, c("escapeProb", "escapes"), list(predsEscs, escs)) + # Ignite - accounting for spatial resolution of models + + # disaggregate the coarse raster to size of flammableRTM + # draw ignitions/escapes from smaller pixel size + # The fine-to-coarse cell mapping does not change within a run, so it is computed once (in mod$). + igRasDT <- fineCoarseTable(coarseToFineMap(sim$ignitionFitRTM, sim$flammableRTM, store = mod), + sim$flammableRTM) + + # nomatch = NULL --> removes pixels that aren't in igCov, which are non flammable + igs <- igRasDT[igCov, on = c("chunkyPixels" = "pixelID"), nomatch = NULL] + # randomly sample + # use unique because of multiple pixelID per chunkyPixel + drawTable <- unique(igs[ignitions > 0, .(chunkyPixels, ignitions, escapes)]) + pixelID_igs <- lapply(drawTable$chunkyPixels, + FUN = function(n, draw = drawTable, ig = igs) { + sampledChunk <- draw[chunkyPixels == n] + pixelID_pop <- igs[chunkyPixels == sampledChunk$chunkyPixels] + drawn <- sample(pixelID_pop$pixelID, size = sampledChunk$ignitions) + igPixels <- try(ig[pixelID %in% drawn, .(pixelID, igProb, ignitions, escapeProb, escapes, + chunkyPixels)]) + return(igPixels) + } + ) |> + rbindlist() #will this fail with zero ignitions? + + #for posterior analysis + igProbRas <- rast(sim$ignitionFitRTM) + igProbRas[igCov$pixelID] <- igCov$igProb + escapeProbRas <- igProbRas + escapeProbRas[igCov$pixelID] <- igCov$escapeProb + sim$fireSense_IgAndEscapeProbRas <- c(igProbRas, escapeProbRas) + names(sim$fireSense_IgAndEscapeProbRas) <- c("ignitionProb", "escapeProb") + + if (!is.na(P(sim)$.saveInterval)) { + #TODO: implement proper plotting control + Plots(igProbRas, types = Par$.plots, filename = paste0("IgnitionProbability_yr", time(sim))) + } + ## `escapes` counts the coarse pixel's escapes and is repeated on each of its ignitions, so which of + ## them escaped is drawn here: exactly `escapes` of the coarse pixel's rows. Drawn after every pixel + ## is placed, so the placements do not change. + if (NROW(pixelID_igs)) { + pixelID_igs[, escaped := seq_len(.N) %in% sample.int(.N, min(escapes[1], .N)), by = "chunkyPixels"] + set(pixelID_igs, NULL, "chunkyPixels", NULL) + } + randomOrder <- sample(1:nrow(pixelID_igs)) + sim$ignitionsAndEscapes <- pixelID_igs[randomOrder,] #Randomize order + + return(invisible(sim)) +} + +#' Supply default inputs +#' +#' There are none. +#' +#' @param sim A `simList`. +#' +#' @return The `simList`, invisibly. +.inputObjects <- function(sim) { + return(invisible(sim)) +} + + +# Standardize `covariates` with the center and scale the fit used (`scaleData`, the attributes of +# the `scale()`d fitting covariates), not with their own. `pixelID` is a cell number, left alone. +scaleAsFit <- function(covariates, scaleData, fittedName) { + if (is.null(scaleData)) { + stop("rescaleVars is TRUE but sim$", fittedName, "$scaleData is NULL; ", + "the covariates cannot be standardized as they were for the fit.") + } + covariates <- copy(covariates) + center <- scaleData[["scaled:center"]] + scale <- scaleData[["scaled:scale"]] + for (v in setdiff(intersect(names(center), colnames(covariates)), "pixelID")) { + set(covariates, NULL, v, (covariates[[v]] - center[[v]]) / scale[[v]]) + } + covariates +} + +#' The fitted models, per ELF +#' +#' With `sim$fireSense_IgnitionFittedList` and `sim$fireSense_EscapeFittedList` (named by `ELFind`), each +#' coarse pixel is assigned to its ELF from `sim$rasterToMatchLargeELF` (the value at the pixel's centre) +#' and gets that ELF's models. Otherwise all pixels get `sim$fireSense_IgnitionFitted` and +#' `sim$fireSense_EscapeFitted`. +#' +#' @param sim A `simList`. +#' @param pixelID the cells of `sim$ignitionFitRTM` to predict. +#' @return list, one element per fit, each with `ign`, `esc` and `rows` (indices into `pixelID`). +ignitionFitsByELF <- function(sim, pixelID) { + ignL <- sim$fireSense_IgnitionFittedList + if (length(ignL) > 1L) { + escL <- sim$fireSense_EscapeFittedList + if (!setequal(names(ignL), names(escL))) + stop("fireSense_ignitionPredict: fireSense_IgnitionFittedList and fireSense_EscapeFittedList must name ", + "the same ELFs") + if (is.null(sim$rasterToMatchLargeELF)) + stop("fireSense_ignitionPredict: several ignition fits need sim$rasterToMatchLargeELF to say which ELF ", + "each pixel is in") + elfCoarse <- postProcess(sim$rasterToMatchLargeELF, to = sim$ignitionFitRTM, method = "near") + v <- terra::values(elfCoarse[[1]], mat = FALSE)[pixelID] + lv <- terra::levels(elfCoarse[[1]])[[1]] + elf <- if (is.data.frame(lv) && NCOL(lv) >= 2) as.character(lv[[2]][match(v, lv[[1]])]) else as.character(v) + noELF <- sum(!elf %in% names(ignL)) + if (noELF > 0) + warning("fireSense_ignitionPredict: ", noELF, " coarse pixels are in no ELF with an ignition fit; ", + "they get no ignitions", call. = FALSE) + return(lapply(names(ignL), function(id) + list(ign = ignL[[id]], esc = escL[[id]], rows = which(elf == id)))) + } + list(list(ign = sim$fireSense_IgnitionFitted, esc = sim$fireSense_EscapeFitted, + rows = seq_along(pixelID))) +} + +## Mean over the K-fold models of one fit's predictions +foldMeanPrediction <- function(fit, newdata, clamp01 = FALSE) { + mods <- fit$modelList$model + modsOnly <- mods[grep("Fold", names(mods))] + if (is.null(modsOnly) || !length(modsOnly)) stop("Not tested anymore") + preds <- lapply(modsOnly, function(model) { + p <- predict(model, newdata = newdata) + if (clamp01) pmax(pmin(1, p), 0) else p + }) + rowMeans(do.call(cbind, preds)) +} + +#' Which coarse cell each fine cell falls in +#' +#' Regridding the coarse ignition raster onto `flammableRTM` ("near", because the cells may not be +#' round multiples) took about 3 s a year at 6.7M cells, and the mapping never changes within a run. +#' It is computed once, from the coarse cell numbers, and kept in `store`; it is rebuilt if the extent, +#' dimensions or crs of either raster change. +#' +#' @param coarse,fine `SpatRaster`s: `ignitionFitRTM` and `flammableRTM`. +#' @param store An environment to keep the mapping in (the module's `mod`). +#' +#' @return A vector with one element per fine cell: its coarse cell number, `NA` outside the coarse raster. +coarseToFineMap <- function(coarse, fine, store) { + gridKey <- function(r) list(as.vector(terra::ext(r)), dim(r), terra::crs(r)) + key <- list(gridKey(coarse), gridKey(fine)) + if (!is.null(store$coarseToFine) && identical(store$coarseToFine$key, key)) + return(store$coarseToFine$map) + + coarseIds <- rast(coarse) + coarseIds[] <- seq_len(ncell(coarseIds)) + coarseIds <- postProcess(coarseIds, to = fine, method = "near") + map <- as.vector(terra::values(coarseIds, mat = FALSE)) + store$coarseToFine <- list(key = key, map = map) + map +} + +#' The fine cells and their coarse cells, for one year +#' +#' @param map The result of `coarseToFineMap()`. +#' @param fine `flammableRTM`: cells not equal to 1 are left out. +#' +#' @return A `data.table` with `pixelID` (fine cell) and `chunkyPixels` (coarse cell). +fineCoarseTable <- function(map, fine) { + flam <- fine[] + keep <- which(!is.na(map) & !(!is.na(flam) & flam != 1)) + data.table(pixelID = keep, chunkyPixels = map[keep]) +} diff --git a/fireSense_ignitionPredict.Rmd b/fireSense_ignitionPredict.Rmd new file mode 100644 index 0000000..2f559b1 --- /dev/null +++ b/fireSense_ignitionPredict.Rmd @@ -0,0 +1,111 @@ +--- +title: "fireSense_ignitionPredict Manual" +subtitle: "v.`r SpaDES.core::moduleMetadata(module = 'fireSense_ignitionPredict', path = '..')$version`" +date: "Last updated: `r Sys.Date()`" +output: + bookdown::html_document2: + toc: true + toc_float: true + theme: sandstone + number_sections: false + df_print: paged + keep_md: yes +editor_options: + chunk_output_type: console +bibliography: citations/references_fireSense_ignitionPredict.bib +link-citations: true +always_allow_html: true +--- + +# fireSense_ignitionPredict Module + + +(ref:fireSense-ignitionPredict) *fireSense_ignitionPredict* + +```{r setup-fireSense-ignitionPredict, include=FALSE} +knitr::opts_chunk$set(echo = TRUE, eval = FALSE, results = "hold") ## change to eval = TRUE if all chunks are to be evaluated + +dir.create("figures", showWarnings = FALSE) + +download.file(url = "https://img.shields.io/badge/Made%20with-Markdown-1f425f.png", + destfile = "figures/markdownBadge.png", + mode = "wb") +``` + +[![made-with-Markdown](figures/markdownBadge.png)](https://commonmark.org) + + + +#### Authors: + +`r paste(as.character(SpaDES.core::moduleMetadata(module = "fireSense_ignitionPredict", path = '..')$authors), sep = ', ')` + + +## Module Overview + +### Module summary + +Each year, predicts ignitions and escapes from the models fitted by *fireSense_ignitionFit* and *fireSense_EscapeFit*, for the ignition component of fireSense [@Marchal:2017a; @Marchal:2017b; @Marchal:2019]. + +1. The covariates in `fireSense_igAndEscapePred_Covariates` are rescaled with `fireSenseUtils::prepareCovariatesOuter()`, the function used for fitting (`rescaleVars`, `modelAlgorithm`). +2. Expected ignitions per coarse pixel are the mean of the predictions of the per-fold ignition models; the number of ignitions is drawn from a Poisson. +3. For coarse pixels with ignitions, the escape probability is the mean of the per-fold escape models, clamped to [0, 1]; escapes are drawn from a binomial with size = ignitions. +4. Each ignition is placed in a randomly chosen flammable pixel of `flammableRTM` inside its coarse pixel. + +Only `xgboost` models are supported. + +### Module inputs and parameters + +`ignitionFitRTM` (the coarse raster used for fitting, from *fireSense_dataPrepFit*) is also read from the `simList`, though it is not declared as an input. +`modelAlgorithm` and `rescaleVars` must have the same value in every module that defines them. + +Table \@ref(tab:moduleInputs-fireSense-ignitionPredict) shows the full list of module inputs. + +```{r moduleInputs-fireSense-ignitionPredict, echo = FALSE, eval = TRUE, message = FALSE, warning = FALSE} +df_inputs <- SpaDES.core::moduleInputs("fireSense_ignitionPredict", "..") +knitr::kable(df_inputs, + caption = "List of (ref:fireSense-ignitionPredict) input objects and their description.") |> + kableExtra::kable_styling(latex_options = "scale_down", full_width = TRUE) +``` + +Summary of user-visible parameters (Table \@ref(tab:moduleParams-fireSense-ignitionPredict)) + + +```{r moduleParams-fireSense-ignitionPredict, echo = FALSE, eval = TRUE, message = FALSE, warning = FALSE} +df_params <- SpaDES.core::moduleParams("fireSense_ignitionPredict", "..") +knitr::kable(df_params, caption = "List of (ref:fireSense-ignitionPredict) parameters and their description.") |> + kableExtra::kable_styling(latex_options = "scale_down", full_width = TRUE) +``` + +### Events + +- `init`: schedules `run` at `.runInitialTime`, and `save` at `.saveInitialTime` if that is not `NA`. +- `run`: makes the predictions and draws described above; repeats every `.runInterval`. +- `save`: does nothing but say so. To save the predicted raster, name `fireSense_IgAndEscapeProbRas` in `outputs(sim)`. + +### Plotting + +If `.saveInterval` is not `NA`, the ignition probability raster is plotted each year with `Plots()`. + +### Module outputs + +Description of the module outputs (Table \@ref(tab:moduleOutputs-fireSense-ignitionPredict)). + +```{r moduleOutputs-fireSense-ignitionPredict, echo = FALSE, eval = TRUE, message = FALSE, warning = FALSE} +df_outputs <- SpaDES.core::moduleOutputs("fireSense_ignitionPredict", "..") +knitr::kable(df_outputs, caption = "List of (ref:fireSense-ignitionPredict) outputs and their description.") |> + kableExtra::kable_styling(latex_options = "scale_down", full_width = TRUE) +``` + +### Links to other modules + +Runs after *fireSense_dataPrepPredict*, which supplies the covariates. `ignitionsAndEscapes` is used by *fireSense* to start fires. +It is normally run as part of the [fireSense](https://github.com/PredictiveEcology/fireSense) module group. + +### Getting help + +- + +## References + + diff --git a/fireSense_IgnitionPredict.Rproj b/fireSense_ignitionPredict.Rproj similarity index 100% rename from fireSense_IgnitionPredict.Rproj rename to fireSense_ignitionPredict.Rproj diff --git a/fireSense_IgnitionPredict.html b/fireSense_ignitionPredict.html similarity index 99% rename from fireSense_IgnitionPredict.html rename to fireSense_ignitionPredict.html index 349e057..0ed16ed 100644 --- a/fireSense_IgnitionPredict.html +++ b/fireSense_ignitionPredict.html @@ -11,7 +11,7 @@ -fireSense_IgnitionPredict Manual +fireSense_ignitionPredict Manual