From c1080e7cc31fe1f95722a10092c4c5510f580b80 Mon Sep 17 00:00:00 2001 From: Eliot McIntire Date: Mon, 28 Sep 2026 11:39:18 -0700 Subject: [PATCH 1/5] New fuelCovariates option: dom/sec/other AGB + treedWetland_agb prepare_SpreadFit() (fireSense_dataPrepFit.R ~690) built the spread covariate table with fireSenseUtils::fireSenseCovariatesCreate() but never passed rstLCC, so treedWetland never appeared, and there was no way to ask for the new dom/sec/other AGB fuel representation added in fireSenseUtils#98. New parameter fuelCovariates (default "domSecOther") passes rstLCC and picks the representation. The dominant/secondary fuel classes are chosen once per ELF, from the most recent data year, via the new fireSenseUtils::chooseDomSecFuelClasses(), and recorded in sim$fuelClassRoles so every data year's covariates use the same two classes. chooseDomSecFuelClasses() is added to the prepSpreadFitData cache key (.useCacheArgs), matching PR #47. fuelCovariates = "species" keeps the previous one-column-per-fuel-class behaviour. Version 1.2.0.9016. Floors fireSenseUtils@development (>= 0.2.3.9053). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01CwcjqqK59FmTJscyi7xUqv --- NEWS.md | 10 +++- fireSense_dataPrepFit.R | 50 ++++++++++++++--- fireSense_dataPrepFit.html | 39 ++++++++++++-- fireSense_dataPrepFit.md | 15 +++++- tests/testthat/test-domSecOtherFuels.R | 74 ++++++++++++++++++++++++++ tests/testthat/test-metadata.R | 3 +- 6 files changed, 177 insertions(+), 14 deletions(-) create mode 100644 tests/testthat/test-domSecOtherFuels.R diff --git a/NEWS.md b/NEWS.md index a942740..5d131d2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,14 @@ # fireSense_dataPrepFit (development version) -- A cached `prepSpreadFitData` event, or cached `harmonizeFireData()` call, now re-runs when a fireSenseUtils function it calls changes: they are keyed on those functions (`.useCacheArgs`, `fireSenseUtils::harmonizeFireDataDeps()`). Requires fireSenseUtils >= 0.2.3.9053. +- New parameter `fuelCovariates` (default `"domSecOther"`): `prepare_SpreadFit()` now builds the + spread covariates as `dom_agb_`/`sec_agb_` (the ELF's two fuel classes with the + most total treed AGB), `other_agb` and `treedWetland_agb`, chosen once per ELF by the new + `fireSenseUtils::chooseDomSecFuelClasses()` and recorded in `sim$fuelClassRoles`. `rstLCC` is + now passed to `fireSenseCovariatesCreate()` (previously never passed, so `treedWetland` never + appeared). `fuelCovariates = "species"` keeps the previous one-column-per-fuel-class behaviour. + `chooseDomSecFuelClasses()` is added to the `prepSpreadFitData` cache key (`.useCacheArgs`). + Needs `fireSenseUtils@development (>= 0.2.3.9053)`. Version 1.2.0.9016. +- A cached `prepSpreadFitData` event, or cached `harmonizeFireData()` call, now re-runs when a fireSenseUtils function it calls changes: they are keyed on those functions (`.useCacheArgs`, `fireSenseUtils::harmonizeFireDataDeps()`). Requires fireSenseUtils >= 0.2.3.9053. Version 1.2.0.9015. - `spreadFitFilename` now defaults to `"latest"`: each polygon's fit comes from the most recent ledger file in `spreadFitGoogleDriveFolder` that has it (`fireSenseUtils::latestSpreadFits()`, which reads only the current model's files, `fireSenseParams_*.rds`). So "this ELF has a diff --git a/fireSense_dataPrepFit.R b/fireSense_dataPrepFit.R index 29e16fe..4f5001d 100644 --- a/fireSense_dataPrepFit.R +++ b/fireSense_dataPrepFit.R @@ -8,7 +8,7 @@ defineModule(sim, list( person(c("Alex", "M"), "Chubaty", role = "ctb", email = "achubaty@for-cast.ca") ), childModules = character(0), - version = list(fireSense_dataPrepFit = "1.2.0.9015"), + version = list(fireSense_dataPrepFit = "1.2.0.9016"), timeframe = as.POSIXlt(c(NA, NA)), timeunit = "year", citation = list("citation.bib"), @@ -67,6 +67,15 @@ defineModule(sim, list( "named `FuelClass` exists in the `LandR::sppEquivalencies_CA` and will be used ", "by default. To change the `FuelClass` classifications, add a column to that table, ", "or to `sim$sppEquiv` and then modify this `fuelClassCol` parameter"), + defineParameter("fuelCovariates", "character", c("domSecOther", "species"), NA, NA, + paste("How the spread-fit fuel covariates are represented. `\"domSecOther\"` (default):", + "exactly four AGB columns per ELF, `dom_agb_` and `sec_agb_` (the", + "two fuel classes with the most total treed AGB over the fit study area),", + "`other_agb` (the rest, pooled) and `treedWetland_agb` (all tree AGB on treed-wetland", + "pixels, removed from the other three there); see", + "`fireSenseUtils::fireSenseCovariatesCreate()`. `\"species\"`: the previous one", + "column per fuel class. `fireSense_dataPrepPredict` follows whichever a fit used;", + "this is not a parameter there.")), defineParameter("minBufferSize", "numeric", 5000, NA, NA, paste("Minimum number of cells in each fire's burned-plus-buffer sample, applied after `areaMultiplier`.")), defineParameter("nonflammableLCC", "numeric", c(0, 20, 31, 32, 33), NA, NA, @@ -103,7 +112,8 @@ defineModule(sim, list( fireSenseUtils::assessFuelClasses, fireSenseUtils::fuelClassPrep, fireSenseUtils::makeLandcoverDT, fireSenseUtils::makeTSD))), prepSpreadFitData = list(.cacheExtra = quote(c(list( - fireSenseUtils::bufferToArea, fireSenseUtils::climateRasterToDataTable, + fireSenseUtils::bufferToArea, fireSenseUtils::chooseDomSecFuelClasses, + fireSenseUtils::climateRasterToDataTable, fireSenseUtils::fireSenseCovariatesCreate, fireSenseUtils::harmonizeFireData, fireSenseUtils::makeMutuallyExclusive, fireSenseUtils::rasterFireBufferDT, fireSenseUtils::rasterFireSpreadPoints), fireSenseUtils::harmonizeFireDataDeps())))), @@ -231,6 +241,10 @@ defineModule(sim, list( "List of data.tables, one per `dataYears`, of `pixelID` and the fuel covariates in the fire buffers."), createsOutput("fireSense_spreadFormula", "character", "formula for spread, using climate and vegetation covariates, as character"), + createsOutput("fuelClassRoles", "list", + paste("Only when `fuelCovariates = \"domSecOther\"`: `list(domClass =, secClass =)`,", + "the fuel classes chosen once for this ELF by `fireSenseUtils::chooseDomSecFuelClasses()`.", + "Both `NA` with `fuelCovariates = \"species\"` or when the ELF has no tree fuel class.")), createsOutput("ignitionFirePoints", "SpatVector", paste("The input, in the CRS of `rasterToMatch` and clipped to `studyArea`.")), createsOutput("ignitionFitRTM", "SpatRaster", @@ -687,10 +701,28 @@ prepare_SpreadFit <- function(sim) { ## when landcoverDT is included, as is the case here, non-forest pixels in cohortData are masked out ## this is necessary when LandR and fireSense have differing concepts of non-forest - dig1 <- .robustDigest(list(sim$landcoverDTs, sim$flammableRTMs)) + dig1 <- .robustDigest(list(sim$landcoverDTs, sim$flammableRTMs, sim$rstLCCs)) dig1a <- .robustDigest(list(sim$cohortDatas, sim$pixelGroupMaps, sim$nonForest_timeSinceDisturbances)) dig2 <- append(dig1, dig1a) - + + fuelCovariates <- match.arg(P(sim)$fuelCovariates, c("domSecOther", "species")) + sim$fuelClassRoles <- list(domClass = NA_character_, secClass = NA_character_) + if (identical(fuelCovariates, "domSecOther")) { + ## chosen once per ELF (the most recent data year, as with sim$rstLCC/sim$rstLCC_RTM elsewhere + ## in this module), not independently for every data year -- a prediction must build the same + ## dom_agb_*/sec_agb_* columns whichever year it is predicting + sim$fuelClassRoles <- Cache(fireSenseUtils::chooseDomSecFuelClasses, + cohortData = tail(sim$cohortDatas, 1)[[1]], + pixelGroupMap = tail(sim$pixelGroupMaps, 1)[[1]], + flammableRTM = tail(sim$flammableRTMs, 1)[[1]], + landcoverDT = tail(sim$landcoverDTs, 1)[[1]], + sppEquiv = sim$sppEquiv, fuelClassCol = P(sim)$fuelClassCol, + sppEquivCol = P(sim)$sppEquivCol, cutoffForYoungAge = P(sim)$cutoffForYoungAge, + .cacheExtra = dig2, omitArgs = c("cohortData", "pixelGroupMap", "flammableRTM", "landcoverDT")) + message("fireSense_dataPrepFit: dominant fuel class = ", sim$fuelClassRoles$domClass, + "; secondary = ", sim$fuelClassRoles$secClass) + } + # This adds youngAge vegData <- Map(f = fireSenseUtils:::fireSenseCovariatesCreate, cohortData = sim$cohortDatas, @@ -698,18 +730,22 @@ prepare_SpreadFit <- function(sim) { flammableRTM = sim$flammableRTMs, landcoverDT = sim$landcoverDTs, nonForest_timeSinceDisturbance = sim$nonForest_timeSinceDisturbances, + rstLCC = sim$rstLCCs, MoreArgs = list(sppEquiv = sim$sppEquiv, sppEquivCol = P(sim)$sppEquivCol, fuelClassCol = P(sim)$fuelClassCol, cutoffForYoungAge = P(sim)$cutoffForYoungAge, missingLCCgroup = sim$missingLCCgroup, nonForestedLCCGroups = sim$nonForestedLCCGroups, + fuelCovariates = fuelCovariates, + domClass = sim$fuelClassRoles$domClass, + secClass = sim$fuelClassRoles$secClass, nonForestCanBeYoungAge = P(sim)$nonForestCanBeYoungAge, studyAreaName = P(sim)$.studyAreaName - ) + ) ) |> - Cache(.cacheExtra = dig2, - omitArgs = c("landcoverDT", "flammableRTM", "cohortData", "pixelGroupMap", "nonForest_timeSinceDisturbance"), + Cache(.cacheExtra = dig2, + omitArgs = c("landcoverDT", "flammableRTM", "cohortData", "pixelGroupMap", "nonForest_timeSinceDisturbance", "rstLCC"), .functionName = "spreadCovariatesCreate") # Add "year" column vegData <- Map(v = vegData, n = names(vegData), function(v, n) { diff --git a/fireSense_dataPrepFit.html b/fireSense_dataPrepFit.html index 5ce18a5..ca62dd3 100644 --- a/fireSense_dataPrepFit.html +++ b/fireSense_dataPrepFit.html @@ -2994,7 +2994,7 @@

fireSense_dataPrepFit Manual

-

v.1.2.0.9014

+

v.1.2.0.9016

Last updated: 2026-09-28

@@ -3004,7 +3004,7 @@

Last updated: 2026-09-28

fireSense_dataPrepFit Module

-

made-with-Markdown

+

made-with-Markdown

Authors:

@@ -3015,7 +3015,7 @@

Module Overview

Prepares the data needed to fit fireSense_IgnitionFit, fireSense_EscapeFit and fireSense_SpreadFit.

Module summary

-

The module combines historical fire records, vegetation, land cover and climate into the covariate tables used to fit the three fireSense processes (Marchal, Steve G. Cumming, et al. 2017b; Marchal, Steve G. Cumming, et al. 2017a; Marchal et al. 2019): ignition, escape (an ignition that grows beyond one pixel) and spread.

+

The module combines historical fire records, vegetation, land cover and climate into the covariate tables used to fit the three fireSense processes (Marchal, Cumming, and McIntire 2017b; Marchal, Cumming, and McIntire 2017a; Marchal, Cumming, and McIntire 2019): ignition, escape (an ignition that grows beyond one pixel) and spread.

Vegetation, land cover and stand age are snapshots, one per year in P(sim)$dataYears (default 2000, 2010, 2020). Each year in P(sim)$fireYears uses the snapshot at or before it, so no fire year may precede the first data year, and every data year needs at least one fire year. Climate is annual and is matched to the year of each fire. @@ -3757,6 +3757,26 @@

Module inputs and parameters

+fuelCovariates + + +character + + +domSecOt…. + + +NA + + +NA + + +How the spread-fit fuel covariates are represented. "domSecOther" (default): exactly four AGB columns per ELF, dom_agb_&lt;class&gt; and sec_agb_&lt;class&gt; (the two fuel classes with the most total treed AGB over the fit study area), other_agb (the rest, pooled) and treedWetland_agb (all tree AGB on treed-wetland pixels, removed from the other three there); see fireSenseUtils::fireSenseCovariatesCreate(). "species": the previous one column per fuel class. fireSense_dataPrepPredict follows whichever a fit used; this is not a parameter there. + + + + minBufferSize @@ -4250,6 +4270,17 @@

Module outputs

+fuelClassRoles + + +list + + +Only when fuelCovariates = "domSecOther": list(domClass =, secClass =), the fuel classes chosen once for this ELF by fireSenseUtils::chooseDomSecFuelClasses(). Both NA with fuelCovariates = "species" or when the ELF has no tree fuel class. + + + + ignitionFirePoints @@ -4470,7 +4501,7 @@

References

Marchal, Jean, Steve G Cumming, and Eliot J B McIntire. 2017b. “Land Cover, More Than Monthly Fire Weather, Drives Fire-Size Distribution in Southern Québec Forests: Implications for Fire Risk Management.” PLoS ONE 12 (6): 1–17. https://doi.org/10.1371/journal.pone.0179294.
-Marchal, Jean, Steven G. Cumming, and Eliot J. B. McIntire. 2019. “Turning Down the Heat: Vegetation Feedbacks Limit Fire Regime Responses to Global Warming.” Ecosystems, ahead of print, May. https://doi.org/10.1007/s10021-019-00398-2. +Marchal, Jean, Steven G. Cumming, and Eliot J. B. McIntire. 2019. “Turning Down the Heat: Vegetation Feedbacks Limit Fire Regime Responses to Global Warming.” Ecosystems, May. https://doi.org/10.1007/s10021-019-00398-2.
diff --git a/fireSense_dataPrepFit.md b/fireSense_dataPrepFit.md index 8a97413..1600a05 100644 --- a/fireSense_dataPrepFit.md +++ b/fireSense_dataPrepFit.md @@ -1,6 +1,6 @@ --- title: "fireSense_dataPrepFit Manual" -subtitle: "v.1.2.0.9014" +subtitle: "v.1.2.0.9016" date: "Last updated: 2026-09-28" output: bookdown::html_document2: @@ -386,6 +386,14 @@ Parameters are in Table \@ref(tab:moduleParams-fireSense-dataPrepFit). NA the column in `sppEquiv` that defines unique fuel classes. A column named `FuelClass` exists in the `LandR::sppEquivalencies_CA` and will be used by default. To change the `FuelClass` classifications, add a column to that table, or to `sim$sppEquiv` and then modify this `fuelClassCol` parameter + + fuelCovariates + character + domSecOt.... + NA + NA + How the spread-fit fuel covariates are represented. `"domSecOther"` (default): exactly four AGB columns per ELF, `dom_agb_<class>` and `sec_agb_<class>` (the two fuel classes with the most total treed AGB over the fit study area), `other_agb` (the rest, pooled) and `treedWetland_agb` (all tree AGB on treed-wetland pixels, removed from the other three there); see `fireSenseUtils::fireSenseCovariatesCreate()`. `"species"`: the previous one column per fuel class. `fireSense_dataPrepPredict` follows whichever a fit used; this is not a parameter there. + minBufferSize numeric @@ -628,6 +636,11 @@ Description of the module outputs (Table \@ref(tab:moduleOutputs-fireSense-dataP character formula for spread, using climate and vegetation covariates, as character + + fuelClassRoles + list + Only when `fuelCovariates = "domSecOther"`: `list(domClass =, secClass =)`, the fuel classes chosen once for this ELF by `fireSenseUtils::chooseDomSecFuelClasses()`. Both `NA` with `fuelCovariates = "species"` or when the ELF has no tree fuel class. + ignitionFirePoints SpatVector diff --git a/tests/testthat/test-domSecOtherFuels.R b/tests/testthat/test-domSecOtherFuels.R new file mode 100644 index 0000000..256d34b --- /dev/null +++ b/tests/testthat/test-domSecOtherFuels.R @@ -0,0 +1,74 @@ +## fireSense_dataPrepFit.R ~690 (prepare_SpreadFit()): fireSenseCovariatesCreate() was never given +## `rstLCC`, so `treedWetland` never appeared, and there was no way to ask for the new +## dom/sec/other AGB fuel representation. `fuelCovariates` (default "domSecOther") now picks the +## representation, and the dominant/secondary classes are chosen once per ELF (not once per data +## year, or every prediction would build a different pair of columns) via +## fireSenseUtils::chooseDomSecFuelClasses(), stored in sim$fuelClassRoles. + +## generic AST walk: apply `f` to every call node in `expr`, recursing into every part +walkCalls <- function(expr, f) { + if (is.call(expr)) { + f(expr) + for (part in as.list(expr)) if (!missing(part) && !is.null(part)) walkCalls(part, f) + } + invisible(NULL) +} + +test_that("fuelCovariates defaults to domSecOther, with species as the only other choice", { + md <- SpaDES.core::moduleMetadata(module = moduleName, path = modulePath) + def <- stats::setNames(md$parameters$default, md$parameters$paramName) + expect_identical(def$fuelCovariates, c("domSecOther", "species")) +}) + +test_that("reqdPkgs floors fireSenseUtils at >= 0.2.3.9053 (chooseDomSecFuelClasses etc.)", { + md <- SpaDES.core::moduleMetadata(module = moduleName, path = modulePath) + fsu <- grep("fireSenseUtils", md$reqdPkgs, value = TRUE) + expect_length(fsu, 1L) + expect_match(fsu, "0\\.2\\.3\\.9053") +}) + +test_that("prepare_SpreadFit() picks fuelClassRoles once per ELF via chooseDomSecFuelClasses()", { + body <- body(prepare_SpreadFit) + found <- FALSE + walkCalls(body, function(e) { + if (identical(deparse(e[[1]]), "<-") && is.call(e[[2]]) && + identical(deparse(e[[2]]), "sim$fuelClassRoles") && + any(grepl("chooseDomSecFuelClasses", deparse(e[[3]]), fixed = TRUE))) + found <<- TRUE + }) + expect_true(found) +}) + +test_that("chooseDomSecFuelClasses() is asked about one representative data year, not every year", { + ## "once per ELF": cohortData/pixelGroupMap/flammableRTM/landcoverDT are each a single tail() + ## element, not the per-data-year lists (sim$cohortDatas etc.) fireSenseCovariatesCreate()'s + ## Map() call uses. + body <- body(prepare_SpreadFit) + callTxt <- NULL + walkCalls(body, function(e) { + if (identical(deparse(e[[1]]), "<-") && is.call(e[[2]]) && + identical(deparse(e[[2]]), "sim$fuelClassRoles") && + any(grepl("chooseDomSecFuelClasses", deparse(e[[3]]), fixed = TRUE))) + callTxt <<- gsub("\\s+", " ", paste(deparse(e[[3]]), collapse = " ")) + }) + expect_match(callTxt, "tail(sim$cohortDatas, 1)", fixed = TRUE) + expect_false(grepl("cohortData = sim$cohortDatas,", callTxt, fixed = TRUE)) +}) + +test_that("the fireSenseCovariatesCreate() Map() call passes rstLCC, fuelCovariates, domClass, secClass", { + body <- body(prepare_SpreadFit) + mapCall <- NULL + walkCalls(body, function(e) { + if (identical(deparse(e[[1]]), "Map") && !is.null(names(e)) && "f" %in% names(e) && + grepl("fireSenseCovariatesCreate", deparse(e[["f"]]), fixed = TRUE)) + mapCall <<- e + }) + expect_false(is.null(mapCall)) + expect_true("rstLCC" %in% names(mapCall)) + expect_identical(deparse(mapCall[["rstLCC"]]), "sim$rstLCCs") + + moreArgsTxt <- gsub("\\s+", " ", paste(deparse(mapCall[["MoreArgs"]]), collapse = " ")) + expect_match(moreArgsTxt, "fuelCovariates = fuelCovariates", fixed = TRUE) + expect_match(moreArgsTxt, "domClass = sim$fuelClassRoles$domClass", fixed = TRUE) + expect_match(moreArgsTxt, "secClass = sim$fuelClassRoles$secClass", fixed = TRUE) +}) diff --git a/tests/testthat/test-metadata.R b/tests/testthat/test-metadata.R index 96fdbf3..3ff5e14 100644 --- a/tests/testthat/test-metadata.R +++ b/tests/testthat/test-metadata.R @@ -59,6 +59,7 @@ test_that("outputs are the expected names and classes", { fireSense_spreadFormula = "character", flammableRTM = "SpatRaster", flammableRTMs = "list", + fuelClassRoles = "list", fuelClassTable = "data.table", ignitionFirePoints = "SpatVector", ignitionFitRTM = "SpatRaster", @@ -93,7 +94,7 @@ test_that("parameters are the expected names", { sort(c(".studyAreaName", ".useCache", ".useCacheArgs", "areaMultiplier", "bufferForFireRaster", "cutoffForYoungAge", "dataYears", "escapeSizeHa", "estimateFuelClasses", "fireYears", "flammabilityThreshold", - "forestedLCC", "fuelClassCol", "igAggFactor", + "forestedLCC", "fuelClassCol", "fuelCovariates", "igAggFactor", "minBufferSize", "nonflammableLCC", "nonForestCanBeYoungAge", "sppEquivCol", "spreadFitFilename", "spreadFitGoogleDriveFolder", "targetFuelClasses", From e8a974335a9222aab10ffc14d5a9fe1a37391f0d Mon Sep 17 00:00:00 2001 From: Eliot McIntire Date: Mon, 28 Sep 2026 11:46:32 -0700 Subject: [PATCH 2/5] Floor fireSenseUtils >= 0.2.3.9055 (the fuel PR #98 was renumbered after development moved) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01CwcjqqK59FmTJscyi7xUqv --- NEWS.md | 4 ++-- fireSense_dataPrepFit.R | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NEWS.md b/NEWS.md index 5d131d2..ab2edda 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,8 +7,8 @@ now passed to `fireSenseCovariatesCreate()` (previously never passed, so `treedWetland` never appeared). `fuelCovariates = "species"` keeps the previous one-column-per-fuel-class behaviour. `chooseDomSecFuelClasses()` is added to the `prepSpreadFitData` cache key (`.useCacheArgs`). - Needs `fireSenseUtils@development (>= 0.2.3.9053)`. Version 1.2.0.9016. -- A cached `prepSpreadFitData` event, or cached `harmonizeFireData()` call, now re-runs when a fireSenseUtils function it calls changes: they are keyed on those functions (`.useCacheArgs`, `fireSenseUtils::harmonizeFireDataDeps()`). Requires fireSenseUtils >= 0.2.3.9053. Version 1.2.0.9015. + Needs `fireSenseUtils@development (>= 0.2.3.9055)`. Version 1.2.0.9016. +- A cached `prepSpreadFitData` event, or cached `harmonizeFireData()` call, now re-runs when a fireSenseUtils function it calls changes: they are keyed on those functions (`.useCacheArgs`, `fireSenseUtils::harmonizeFireDataDeps()`). Requires fireSenseUtils >= 0.2.3.9055. Version 1.2.0.9015. - `spreadFitFilename` now defaults to `"latest"`: each polygon's fit comes from the most recent ledger file in `spreadFitGoogleDriveFolder` that has it (`fireSenseUtils::latestSpreadFits()`, which reads only the current model's files, `fireSenseParams_*.rds`). So "this ELF has a diff --git a/fireSense_dataPrepFit.R b/fireSense_dataPrepFit.R index 4f5001d..63373ba 100644 --- a/fireSense_dataPrepFit.R +++ b/fireSense_dataPrepFit.R @@ -17,7 +17,7 @@ defineModule(sim, list( reqdPkgs = list("data.table", "fastDummies", "Require", "PredictiveEcology/reproducible@development (>= 3.2.1.9042)", # CacheGeo re-reads a changed local file "PredictiveEcology/climateData@development (>= 2.2.3.9006)", - "PredictiveEcology/fireSenseUtils@development (>= 0.2.3.9053)", + "PredictiveEcology/fireSenseUtils@development (>= 0.2.3.9055)", "FOR-CAST/fireregimetools@main (>= 0.1.0.9008)", "ggplot2", "parallel", "purrr", "raster", "sf", "sp", "PredictiveEcology/LandR@development (>= 1.2.0.9015)", From 32d2dc5668e5487c9b987ba5be39393c7ba8f851 Mon Sep 17 00:00:00 2001 From: Eliot McIntire Date: Mon, 28 Sep 2026 11:46:54 -0700 Subject: [PATCH 3/5] NEWS: restore the #47 entry's own floor (0.2.3.9053) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01CwcjqqK59FmTJscyi7xUqv --- NEWS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index ab2edda..ffe6e56 100644 --- a/NEWS.md +++ b/NEWS.md @@ -8,7 +8,7 @@ appeared). `fuelCovariates = "species"` keeps the previous one-column-per-fuel-class behaviour. `chooseDomSecFuelClasses()` is added to the `prepSpreadFitData` cache key (`.useCacheArgs`). Needs `fireSenseUtils@development (>= 0.2.3.9055)`. Version 1.2.0.9016. -- A cached `prepSpreadFitData` event, or cached `harmonizeFireData()` call, now re-runs when a fireSenseUtils function it calls changes: they are keyed on those functions (`.useCacheArgs`, `fireSenseUtils::harmonizeFireDataDeps()`). Requires fireSenseUtils >= 0.2.3.9055. Version 1.2.0.9015. +- A cached `prepSpreadFitData` event, or cached `harmonizeFireData()` call, now re-runs when a fireSenseUtils function it calls changes: they are keyed on those functions (`.useCacheArgs`, `fireSenseUtils::harmonizeFireDataDeps()`). Requires fireSenseUtils >= 0.2.3.9053. Version 1.2.0.9015. - `spreadFitFilename` now defaults to `"latest"`: each polygon's fit comes from the most recent ledger file in `spreadFitGoogleDriveFolder` that has it (`fireSenseUtils::latestSpreadFits()`, which reads only the current model's files, `fireSenseParams_*.rds`). So "this ELF has a From e641f5342ae5525709d6a56ee2d90d0a8b7ca9d6 Mon Sep 17 00:00:00 2001 From: Eliot McIntire Date: Mon, 28 Sep 2026 11:56:36 -0700 Subject: [PATCH 4/5] Floor fireSenseUtils >= 0.2.3.9057 (fuel PR #98 renumbered on top of #100) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01CwcjqqK59FmTJscyi7xUqv --- NEWS.md | 2 +- fireSense_dataPrepFit.R | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS.md b/NEWS.md index ffe6e56..82732db 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,7 +7,7 @@ now passed to `fireSenseCovariatesCreate()` (previously never passed, so `treedWetland` never appeared). `fuelCovariates = "species"` keeps the previous one-column-per-fuel-class behaviour. `chooseDomSecFuelClasses()` is added to the `prepSpreadFitData` cache key (`.useCacheArgs`). - Needs `fireSenseUtils@development (>= 0.2.3.9055)`. Version 1.2.0.9016. + Needs `fireSenseUtils@development (>= 0.2.3.9057)`. Version 1.2.0.9016. - A cached `prepSpreadFitData` event, or cached `harmonizeFireData()` call, now re-runs when a fireSenseUtils function it calls changes: they are keyed on those functions (`.useCacheArgs`, `fireSenseUtils::harmonizeFireDataDeps()`). Requires fireSenseUtils >= 0.2.3.9053. Version 1.2.0.9015. - `spreadFitFilename` now defaults to `"latest"`: each polygon's fit comes from the most recent ledger file in `spreadFitGoogleDriveFolder` that has it (`fireSenseUtils::latestSpreadFits()`, which reads only the diff --git a/fireSense_dataPrepFit.R b/fireSense_dataPrepFit.R index 63373ba..fbda1bc 100644 --- a/fireSense_dataPrepFit.R +++ b/fireSense_dataPrepFit.R @@ -17,7 +17,7 @@ defineModule(sim, list( reqdPkgs = list("data.table", "fastDummies", "Require", "PredictiveEcology/reproducible@development (>= 3.2.1.9042)", # CacheGeo re-reads a changed local file "PredictiveEcology/climateData@development (>= 2.2.3.9006)", - "PredictiveEcology/fireSenseUtils@development (>= 0.2.3.9055)", + "PredictiveEcology/fireSenseUtils@development (>= 0.2.3.9057)", "FOR-CAST/fireregimetools@main (>= 0.1.0.9008)", "ggplot2", "parallel", "purrr", "raster", "sf", "sp", "PredictiveEcology/LandR@development (>= 1.2.0.9015)", From 10fd88ef0e4001cf7b94cede7498d398d7558100 Mon Sep 17 00:00:00 2001 From: Eliot McIntire Date: Mon, 28 Sep 2026 12:55:31 -0700 Subject: [PATCH 5/5] test: the fireSenseUtils floor is 0.2.3.9057 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01CwcjqqK59FmTJscyi7xUqv --- tests/testthat/test-domSecOtherFuels.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testthat/test-domSecOtherFuels.R b/tests/testthat/test-domSecOtherFuels.R index 256d34b..775183e 100644 --- a/tests/testthat/test-domSecOtherFuels.R +++ b/tests/testthat/test-domSecOtherFuels.R @@ -20,11 +20,11 @@ test_that("fuelCovariates defaults to domSecOther, with species as the only othe expect_identical(def$fuelCovariates, c("domSecOther", "species")) }) -test_that("reqdPkgs floors fireSenseUtils at >= 0.2.3.9053 (chooseDomSecFuelClasses etc.)", { +test_that("reqdPkgs floors fireSenseUtils at >= 0.2.3.9057 (chooseDomSecFuelClasses etc.)", { md <- SpaDES.core::moduleMetadata(module = moduleName, path = modulePath) fsu <- grep("fireSenseUtils", md$reqdPkgs, value = TRUE) expect_length(fsu, 1L) - expect_match(fsu, "0\\.2\\.3\\.9053") + expect_match(fsu, "0\\.2\\.3\\.9057") }) test_that("prepare_SpreadFit() picks fuelClassRoles once per ELF via chooseDomSecFuelClasses()", {