From 80ccb1db426a9b60ba654595034ae913a088afd0 Mon Sep 17 00:00:00 2001 From: Gustav Delius Date: Tue, 7 Jul 2026 19:43:09 +0100 Subject: [PATCH] Add mizer 3.2 announcement blog post Covers the two reasons for the release: consistent resource setting and the fix that lets extension packages be chained in any load order, with a worked mizerReef + mizerMR example. Also summarises the smaller additions in 3.2. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01EyeA3WdYPB8TFo8Pssh1Kw --- .../mizer-3-2-announcement.Rmd | 216 ++++++++++++++++++ 1 file changed, 216 insertions(+) create mode 100644 posts/2026-07-07-mizer-3-2-announcement/mizer-3-2-announcement.Rmd diff --git a/posts/2026-07-07-mizer-3-2-announcement/mizer-3-2-announcement.Rmd b/posts/2026-07-07-mizer-3-2-announcement/mizer-3-2-announcement.Rmd new file mode 100644 index 0000000..8e298d5 --- /dev/null +++ b/posts/2026-07-07-mizer-3-2-announcement/mizer-3-2-announcement.Rmd @@ -0,0 +1,216 @@ +--- +title: "Announcing mizer 3.2" +description: | + A quick follow-up to mizer 3.1 that fixes two things we were not happy to + leave standing: the resource-setting functions behaved inconsistently, and a + flaw in the extension mechanism prevented two extension packages from being + chained together. Along the way 3.2 also brings a handful of new analysis + functions and cheatsheets. +author: + - name: Gustav Delius +date: 2026-07-07 +output: + distill::distill_article: + self_contained: false + toc: true +--- + +```{r setup, include=FALSE} +knitr::opts_chunk$set(echo = TRUE, eval = FALSE) +``` + +We released [mizer 3.1](https://blog.mizer.sizespectrum.org/posts/2026-06-26-mizer-3-1-announcement/) +only a few weeks ago, so why 3.2 already? Two reasons, and both are the kind of +thing that is better fixed sooner than lived with. The first is that the +functions for setting the background resource had grown inconsistent with each +other and with the rest of mizer, in a way that could silently discard your +changes. The second is that the extension mechanism had a structural flaw that +made it impossible to combine two independently developed extension packages in +one model. Neither could wait for the next feature release. + +## Consistent resource setting + +mizer's background resource is described by a few scalar parameters — a +carrying-capacity coefficient `kappa` and exponent `lambda`, a replenishment +rate `r_pp` and exponent `n` — from which mizer builds the size-dependent +capacity (`cc_pp`) and rate (`rr_pp`) arrays that the dynamics actually use. You +can set the model at either level: change a scalar and let mizer rebuild the +arrays, or supply an array directly and have it left alone ("frozen"). + +The problem was that the different ways of doing this did not agree. Setting +species parameters with `species_params<-` rebuilds the affected species rates +from the new values, cleanly and predictably. The resource setters did not +follow the same rule. Some of them tried to *balance* the resource — adjusting +the arrays so that the current community stays exactly at its steady state — +whether or not you asked for it. As a side effect, editing a rate-side scalar +such as `r_pp` could be silently overwritten by the balancing step, so your +change simply vanished. Successive edits could overwrite one another rather than +accumulate. + +mizer 3.2 makes the resource setters behave like the species setters: + +- Assigning to `resource_params()` rebuilds the size-dependent capacity and rate + arrays from the resource parameters, while leaving any array you have set + manually (frozen) untouched. It no longer balances. + +- Balancing the resource to preserve the steady state is now solely the job of + `setResource()`. The individual setters `resource_rate<-`, + `resource_capacity<-`, `resource_level<-` and `resource_dynamics<-` gained a + `balance` argument so you can switch it off explicitly, for example + + ```r + resource_capacity(params, balance = FALSE) <- my_capacity + ``` + +- `setResource()` no longer silently overwrites a frozen rate or capacity array + when it balances. If you have set an array by hand, that array wins and mizer + warns you rather than quietly replacing it. + +The upshot is that setting a resource parameter now does exactly what setting a +species parameter does: it takes effect. If you have code that relied on the old +balancing behaviour, the new +[*Upgrading mizer*](https://sizespectrum.org/mizer/articles/upgrading.html) +vignette explains what changed and how to adapt. + +## Extensions that chain in any order + +mizer's real power comes from its extension packages. Each one — mizerReef for +coral-reef communities, mizerMR for multiple background resources, and others — +registers itself with mizer and contributes its own versions of the rate +functions. When you call a generic such as `getEncounter()`, mizer walks a chain +of extensions, letting each one add its contribution via `NextMethod()`. + +In principle two extensions that touch different parts of the model should +compose: you should be able to run a reef model *and* give it several background +resources. In practice this did not work. Each extension defined its marker +class statically as a direct sibling of `MizerParams` +(`setClass("mizerReef", contains = "MizerParams")`, +`setClass("mizerMR", contains = "MizerParams")`). Two siblings cannot be +arranged into a single inheritance chain, so an object could carry one extension +or the other, but never both. Whichever you applied second could not sit in the +right place in the class hierarchy. + +mizer 3.2 removes the static class. An installed extension is now recognised +from the S3 methods it registers for its marker class (for example +`getEncounter.mizerMR`), rather than from a statically declared S4 class. This +lets mizer build the marker class dynamically when the package is loaded and +insert it into the S4 hierarchy at the correct position relative to whatever +other extensions are already active — in whichever order they were loaded. The +class chain becomes genuinely linear, `mizerMR` extending `mizerReef` extending +`MizerParams` (or the reverse, depending on load order), and both sets of +methods dispatch correctly. + +Here is what that now makes possible. Load both extensions — the one you load +last sits at the front of the chain: + +```r +library(mizerReef) +library(mizerMR) +``` + +Start from mizerReef's example Caribbean reef model, which has a single +background resource plus the reef's algae and detritus components: + +```r +params <- caribbean_3_model +class(params) +#> [1] "mizerReef" +``` + +Now hand the resource over to mizerMR, splitting the single background spectrum +into a small-plankton and a large-plankton pool: + +```r +wf <- w_full(params) +resource_params <- data.frame( + resource = c("small plankton", "large plankton"), + kappa = 1e11, + lambda = 2.05, + w_min = c(min(wf), 1), + w_max = c(1, max(params@w)), + r_pp = 4, + n = 2 / 3 +) +params <- setMultipleResources(params, resource_params = resource_params) +``` + +The returned object now belongs to a class that chains **both** extensions: + +```r +class(params) +#> [1] "mizerMR" +is(params, "mizerReef") +#> [1] TRUE +is(params, "mizerMR") +#> [1] TRUE +``` + +`class()` reports the most-derived class, but the object still inherits from +`mizerReef`, so reef generics and multiple-resource generics both dispatch. You +can give each species its own preference for each resource, retune with +mizerReef's `reefSteady()` — which is blissfully unaware that the background is +now several resources, because mizerMR handles that further down the chain — and +plot the combined model with a single `plotSpectra()` call: + +```r +params <- reefSteady(params) +plotSpectra(params, power = 2) +``` + +Neither package needs to know the other exists; they only need to be polite +about calling `NextMethod()`. The full worked example, including different +per-species resource preferences, is in mizerReef's +[*Combining mizerReef with mizerMR*](https://sizespectrum.org/mizerReef/articles/multiple-resources.html) +vignette, and the mechanics of the chain are described in +`vignette("using-extension-packages", package = "mizer")`. + +## Also in 3.2 + +While the two fixes above were the reason for the release, 3.2 also gathers up a +number of improvements: + +- **`steadyNewton()`** (experimental) finds a steady state by solving the + steady-state equation directly with a Newton-type root finder instead of + running the dynamics to convergence. Unlike `steady()` it converges even when + the steady state is dynamically unstable, and it discovers the support of the + steady state automatically. + +- **`adjustSizeGrid()`** adjusts the size grid of a model to a new minimum and/or + maximum size. It can both expand and truncate the grid, warning if it would + discard non-negligible abundance. + +- **`project()`** gains a `callback` argument, letting you run your own function + at each saved time step. + +- **Nicer output.** Printing a rate array (as returned by `getEncounter()`, + `getBiomass()`, `getFMort()`, `NResource()` and friends) now shows the actual + values, truncated to fit the console, instead of a per-species min/mean/max + summary. Columns accessed with `$` on a `species_params` or `gear_params` + object come back named by species, so you can tell the entries apart. + +- **Fewer surprises with gears.** Setting `sel_func` on a `gear_params` object + now automatically adds the argument columns that selectivity function needs as + `NA` columns, ready to fill in. `plotYieldGear()` gained the `log_x`, `log_y` + and `log` arguments to match `plotYield()`. + +- **Three new cheatsheets** — *Model Setup and Calibration*, *Fishing*, and + *Changing Model Parameters* — join the analysis-and-plotting cheatsheet, which + now covers the newer plotting functions. + +For the complete list see the +[changelog](https://sizespectrum.org/mizer/news/index.html). + +## Upgrading + +```r +install.packages("mizer") +``` + +Existing `MizerParams` and `MizerSim` objects are upgraded automatically when +you load them with `readParams()` or `readSim()`. The one change that may affect +existing scripts is the resource-setting behaviour described above; the +[*Upgrading mizer*](https://sizespectrum.org/mizer/articles/upgrading.html) +vignette walks through it. + +As always, we welcome bug reports and feature requests on +[GitHub](https://github.com/sizespectrum/mizer/issues).