diff --git a/NEWS.md b/NEWS.md index 0e9f0e5..3f42009 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # fireSense_dataPrepFit (development version) +- The strictly-before rule (a fire year uses the latest data year before it) is `fireSenseUtils::dataYearBefore()` and `dataYearElement(before = TRUE)`, shared with the spread objective, which read the tables by "not after" and failed in its first DEoptim generation for fire years equal to a data year; this module's own `vegetationYear()` is gone. Results are unchanged. Floor `fireSenseUtils` raised to 0.2.3.9100 (Depends-on: PredictiveEcology/fireSenseUtils#159). - The `fireYears` default is plain `fireSenseUtils::defaultFireYears()`, which now starts in 1986 (before, this module dropped its first year with `[-1L]`). Floor `fireSenseUtils` raised to 0.2.3.9099, the first version whose `defaultFireYears()` starts in 1986 (PredictiveEcology/fireSenseUtils#158). The default fire years do not change; `fireSense_ELFs` shares them. - Fixed: each fire year is fitted against vegetation from an earlier year. A year's satellite vegetation already shows part of that year's fires (ELF 6.6.2: pixels burned in 2010 have mean biomass 64 in the 2005 vegetation and 26 in the 2010 vegetation, while unburned pixels are near 79 in both), so the fits learned that fire burns where the vegetation already looks burned. A fire year now uses the latest data year strictly before it (1986-1990 use 1985, 1991-2000 use 1990, ...; `yearGroups()`, `lccShareForYear()`, `fitDecisionYear()`'s data year), the decision year of the structure of the model included, and every `fireYears` must be after the first of `dataYears`, with an error otherwise. The `fireYears` default therefore starts in 1986. Fits, ignition and escape alike, must be redone. Prediction is unchanged: it still uses the data year at or before the year. diff --git a/fireSense_dataPrepFit.R b/fireSense_dataPrepFit.R index 4fdeebc..21a92ac 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.9099)", # defaultFireYears() from 1986; dataYearFor(), dataYearElement() + "PredictiveEcology/fireSenseUtils@development (>= 0.2.3.9100)", # dataYearBefore(), dataYearElement(before =); defaultFireYears() from 1986 "FOR-CAST/fireregimetools@main (>= 0.1.0.9008)", "ggplot2", "parallel", "purrr", "raster", "sf", "sp", "PredictiveEcology/LandR@development (>= 1.2.0.9015)", @@ -976,7 +976,7 @@ prepare_SpreadFit <- function(sim) { #' Land-cover shares of flammable pixels, for one year #' #' The land cover is the data year `year`'s vegetation comes from: the latest data year strictly before -#' `year` ([vegetationYear()], the rule [yearGroups()] assigns a vegetation year to each fire year with). Read from the per-year lists `sim$rstLCCs` and `sim$flammableRTMs` (named `year`), +#' `year` ([vegetationDataYear()], the rule [yearGroups()] assigns a vegetation year to each fire year with). Read from the per-year lists `sim$rstLCCs` and `sim$flammableRTMs` (named `year`), #' never from `sim$rstLCC_RTM` and `sim$flammableRTM`: `fireSense_dataPrepPredict` overwrites those two #' with the year it predicts (a hindcast of 1985 sets 1985), and what is a spread covariate of a fit #' must not change with the year predicted. @@ -985,7 +985,7 @@ prepare_SpreadFit <- function(sim) { #' @param year integer, the fire year the shares are for (see [fitDecisionYear()] for a fit). #' @return as `fireSenseUtils::lccFlammableShare()`. lccShareForYear <- function(sim, year) { - el <- fireSenseUtils::dataYearElement(sim$rstLCCs, vegetationYear(year)) + el <- fireSenseUtils::dataYearElement(sim$rstLCCs, year, before = TRUE) fireSenseUtils::lccFlammableShare(sim$rstLCCs[[el]], sim$flammableRTMs[[el]]) } @@ -995,7 +995,7 @@ lccShareForYear <- function(sim, year) { #' non-forest classes are grouped (`assessFuelClasses()`), the dominant and secondary fuel classes #' (`chooseDomSecFuelClasses()`) -- is decided once per ELF, at fit time, for all of `fireYears`, and a #' prediction takes it from the fit's ledger row. It is decided for the last fire year, -#' `max(P(sim)$fireYears)`, whose vegetation data year ([vegetationYear()]) is the latest the fit uses and +#' `max(P(sim)$fireYears)`, whose vegetation data year ([vegetationDataYear()]) is the latest the fit uses and #' the one a prediction starts from. A hindcast's `fireSense_dataPrepFit` run (same `fireYears`, the #' ledger row already there) makes the same decision, whatever its `dataYears` or the year it predicts. #' @@ -1010,7 +1010,7 @@ fitDecisionYear <- function(sim) { #' lists (`cohortDatas`, `rstLCCs`, ...; they share `rstLCCs`' names), `fireSenseUtils::dataYearElement()`. #' @rdname fitDecisionYear fitDecisionYearName <- function(sim) { - fireSenseUtils::dataYearElement(sim$rstLCCs, vegetationYear(fitDecisionYear(sim))) + fireSenseUtils::dataYearElement(sim$rstLCCs, fitDecisionYear(sim), before = TRUE) } #' Fire buffers and ignition points from `historicalFireRaster` @@ -1779,24 +1779,18 @@ cohDat <- "cohortData" pixGM <- "pixelGroupMap" saMap <- "standAgeMap" -#' The latest year whose vegetation a fire year can use +#' The data year whose vegetation each fire year uses #' #' A satellite vegetation year already shows part of that year's fires, so a fit pairs a fire year with -#' vegetation of an earlier year: the year before it, for the data year lookup ([vegetationDataYear()], -#' `fireSenseUtils::dataYearElement()`). This is the one place the module states that rule; prediction +#' the vegetation of an earlier data year. This is the one place the module states that rule, by +#' `fireSenseUtils::dataYearBefore()` (the rule the spread objective reads the tables by); prediction #' keeps `fireSenseUtils::dataYearFor()`'s "not after". #' -#' @param fireYears integer fire years. -#' @return integer, the year to look up the data year of. -vegetationYear <- function(fireYears) fireYears - 1L - -#' The data year whose vegetation each fire year uses -#' #' @param dataYears increasing integer years with vegetation data. #' @param fireYears integer years of fire records. #' @return integer, per fire year the latest of `dataYears` strictly before it (`NA` if none). vegetationDataYear <- function(dataYears, fireYears) { - fireSenseUtils::dataYearFor(dataYears, vegetationYear(fireYears)) + fireSenseUtils::dataYearBefore(dataYears, fireYears) } #' Group fire years by the data year whose vegetation they use diff --git a/tests/testthat/test-lccShareForYear.R b/tests/testthat/test-lccShareForYear.R index adc9648..f6ee5d6 100644 --- a/tests/testthat/test-lccShareForYear.R +++ b/tests/testthat/test-lccShareForYear.R @@ -55,8 +55,8 @@ test_that("the fit's structure decisions use the fit's decision year, not the sh test_that("fitDecisionYearName is the list element of the decision year's data year", { ## P(sim)$fireYears is not available outside a simList: the element rule alone sim <- lccSim() - expect_identical(fireSenseUtils::dataYearElement(sim$rstLCCs, vegetationYear(2024L)), "year2020") - expect_identical(fireSenseUtils::dataYearElement(sim$rstLCCs, vegetationYear(2020L)), "year2010") - expect_true(grepl("dataYearElement(sim$rstLCCs, vegetationYear(fitDecisionYear(sim)))", - paste(deparse(body(fitDecisionYearName)), collapse = " "), fixed = TRUE)) + expect_identical(fireSenseUtils::dataYearElement(sim$rstLCCs, 2024L, before = TRUE), "year2020") + expect_identical(fireSenseUtils::dataYearElement(sim$rstLCCs, 2020L, before = TRUE), "year2010") + expect_true(grepl("dataYearElement(sim$rstLCCs, fitDecisionYear(sim), before = TRUE)", + paste(trimws(deparse(body(fitDecisionYearName))), collapse = " "), fixed = TRUE)) })