This article collects the changes that may require you to update your own code or models when you upgrade to a new release of mizer. Existing model objects created with an earlier version continue to load and run — they are upgraded automatically — so the notes below are about changes in behaviour and in the functions you call, not about stored objects. The changes are grouped by the release in which they took effect, most recent first.
Only changes that can alter the behaviour of existing code are listed. The many purely additive features (new functions, new optional arguments, new plots) are described in the changelog and are not repeated here.
Upgrading from mizer 3.1 to 3.2
species_params<-() now detects and protects
changes
Previously, modifying species parameters via
species_params<-() updated the values in the model but
bypassed given_species_params(). This meant that your
changes were not protected, and any subsequent recalculation of defaults
(for example, by a call to given_species_params<-())
would overwrite your custom values. Furthermore, changing a parameter
like w_inf via species_params<-() did not
automatically trigger a recalculation of downstream parameters like
w_mat or w_max.
Now, species_params<-() intelligently diffs the new
data frame against the old one to detect exactly which parameters you
have changed. It automatically records those changed parameters in
given_species_params, protecting them from future
overwrites, and immediately recalculates any downstream defaults based
on your changes.
How this affects existing code:
If your existing code used
species_params<-()to update a core parameter likew_infand you expectedw_matorw_maxto remain frozen at their old values, you will now see them automatically recalculate. If you wish to freeze downstream parameters, you must provide their frozen values explicitly in the same update.If your code computes custom parameters and saves them via
species_params<-(), those parameters will now be preserved and survive future recalculations.
Setting resource parameters
Two related changes affect how you modify the resource size spectrum. Together they make the resource scalars behave like the species parameters: a scalar is an input, and the size-dependent arrays are computed from it.
Assigning to resource_params() now updates the resource
arrays
Previously, assigning to resource_params() — or to one
of its components, such as
resource_params(params)$kappa <- ... — only stored the
new scalar values. The size-dependent carrying capacity
(cc_pp) and replenishment rate (rr_pp) were
left unchanged until you next called setResource().
Now these assignments immediately rebuild the arrays from the
scalars, exactly as species_params()<- rebuilds the
species rates:
-
kappa,lambdaandw_pp_cutoffrebuild the carrying capacity; -
r_ppandnrebuild the replenishment rate.
Arrays that you have set by hand are left untouched (see Frozen arrays below).
If your code changed a resource scalar and then called
setResource() to apply it, nothing breaks — you can drop
the now-redundant setResource() call. If you changed a
resource scalar and relied on the arrays not changing until
later, review that code.
Assigning to resource_params() does not balance the
resource
Balancing means adjusting the rate and capacity together so
that the resource replenishes at exactly the rate at which it is
consumed, keeping it at its steady state. Assigning to
resource_params() rebuilds the arrays from the scalars but
does not balance, so the resource steady state
generally shifts.
Balancing is now solely a feature of setResource(). To
change a resource coefficient and keep the resource balanced,
call setResource() rather than assigning to
resource_params():
# Rebuild the capacity from a new coefficient and rebalance the rate,
# so the steady state is preserved:
params <- setResource(params, resource_capacity = new_kappa)
# Likewise, set a new rate coefficient and rebalance the capacity:
params <- setResource(params, resource_rate = new_r_pp)The resource setters gained a balance argument
resource_rate<-, resource_capacity<-,
resource_level<- and resource_dynamics<-
still balance by default (unchanged behaviour), but they now accept a
balance argument so you can switch balancing off:
# Set the capacity but leave the rate untouched (do not rebalance):
resource_capacity(params, balance = FALSE) <- my_capacityFrozen arrays are protected from incidental balancing
When you set the size dependence of the resource capacity or the
resource rate by hand (by assigning a full vector rather than a scalar),
mizer marks it “set manually” — it is frozen and will not be
recomputed from the resource parameters. Previously, an operation that
re-balanced the resource without being given a replacement rate
or capacity — for example changing only resource_dynamics,
or calling setResource() with neither a rate nor a capacity
— would silently overwrite such a frozen array. It is now kept, and a
warning is issued instead.
To deliberately recompute a frozen array from the resource
parameters, pass reset = TRUE to
setResource().
The species_params data frame is now an S3
subclass
The species_params data frame now has class
c("species_params", "data.frame") (and
gear_params similarly). It behaves like an ordinary data
frame, but subsetting and subassignment go through class-preserving S3
methods and can trigger reactive re-validation and conversions (for
example filling in a weight from a length). Code that relied on
class(species_params(params)) being exactly
"data.frame", or that stripped attributes with the
assumption of a plain data frame, may need adjusting. When you need a
plain frame, coerce explicitly with as.data.frame().
Accessing a column with $ now returns a named
vector
Extracting a single column from a species_params or
gear_params object with $ now returns a vector
named by species (or by "species, gear" for
gear_params):
species_params(params)$w_mat
#> Sprat Herring Cod
#> ... ... ...The values are unchanged, but the names are new. This is convenient
for identifying entries, but code that compared such a vector with
identical() to an unnamed vector, or that used it as-is
where names matter (for example as row/column names elsewhere), may
behave differently. Strip the names with unname() if you
need the old behaviour. The species column itself is
returned unnamed.
Setting sel_func adds the required argument
columns
Assigning a selectivity function name to a gear_params
object now automatically adds the argument columns that the function
needs (as NA), ready to be filled in:
gp$sel_func <- "sigmoid_length"
# gp now has l25 and l50 columns, both NAPreviously these columns had to be added by hand. Code that checks
which columns are present in gear_params, or that expected
setting sel_func to leave the column set unchanged, will
now see the extra columns (#431).
Passing a data frame to species_params() /
given_species_params() now validates it
Calling species_params() or
given_species_params() on a plain data frame now runs the
same validation and defaults that validSpeciesParams() and
validGivenSpeciesParams() apply, rather than only checking
for misspellings and converting lengths to weights.
species_params(df) fills in the default columns
(w_max, alpha, n, p,
interaction_resource, z_ext, and the rest),
and given_species_params(df) applies the consistency
corrections (for example clamping w_mat below
w_inf), derives w_inf from
w_max/w_repro_max when it is absent, and now
stops if the frame has duplicate species rows. Models built or modified
through newMultispeciesParams(), setParams()
and the species_params()<- /
given_species_params()<- setters are unaffected, because
those already ran this validation. Only code that called the two
accessors directly on a bare data frame will see the extra columns and
stricter checks (#432).
Printing of mizer array objects shows the values
print() on the array objects returned by the rate
getters (ArraySpeciesBySize,
ArrayTimeBySpecies, ArrayResourceBySize,
ArrayTimeByResourceBySize and
ArrayTimeBySpeciesBySize, as returned by
getEncounter(), getBiomass(),
getFMort(), NResource() and similar) now
truncates the output instead of flooding the console with all the array
entries. If your code or reports relied on the old printed format, use
as.data.frame() to go back to the full output.
Upper boundary condition at w_max
The size-spectrum solver now holds the abundance at zero above each
species’ maximum size w_max. Without diffusion this happens
automatically and results are unchanged. With diffusion switched on this
change stops a small amount of density leaking to sizes above
w_max, so results there change slightly. See
vignette("numerical_details").
Extension packages: dynamic marker classes
If you develop a mizer extension, an installed extension package is
now recognised as a dispatching extension from the S3 methods it
registers for its marker class (for example
getEncounter.mizerMR), rather than only from a statically
defined S4 marker class. You can now omit the static
setClass("mizerFoo", contains = "MizerParams") and let
mizer create the marker class dynamically. This lets two independently
developed extensions be chained in either load order. See
vignette("creating-extension-packages").
Upgrading from mizer 3.0 to 3.1
Version 3.1 leaves default results unchanged from 3.0 unless you opt in to the new experimental second-order-in-size scheme. The changes below can still affect existing code in specific situations.
Maximum-size species parameters clarified
The maximum-size parameters have been given clearer, separate roles (#325):
-
w_inf, the von Bertalanffy asymptotic size, is now the primary maximum-size parameter and is used as the default forw_repro_max(the size at which a mature individual invests all its energy in reproduction) and forw_mat. -
w_maxis now purely a computational boundary — it sets the size grid and the plot range — and defaults to1.5 * w_inf. - The default external mortality parameter
z0is now computed fromw_infrather thanw_max, so the computational boundaryw_maxno longer feeds into any model parameter.
Existing models and scripts are unaffected: if w_inf is
not supplied it is taken from w_repro_max or
w_max, so old objects behave as before. However,
new models built from the defaults may differ from
3.0.0. If you build models from scratch, check that
w_inf, w_max and w_repro_max mean
what you intend.
getTrophicLevel() gives the resource a size-dependent
trophic level
getTrophicLevel() and
getTrophicLevelBySpecies() now assign the resource a
size-dependent trophic level, \(T_R(w) =
\max(1,\, 1 + \log(w / w_R) / \log(\beta_R))\), instead of
treating the resource as trophic level 0. The new w_R and
beta_R arguments control this. Trophic levels computed with
these functions will therefore be higher than before. Set the arguments
explicitly if you need to reproduce old numbers.
Bug fixes that change results
Several fixes correct earlier behaviour and so change output:
-
summary()of aMizerSimnow reports the fishing effort that was used during the simulation, rather than the model’sinitial_effort. Gears whose effort varied over time show the mean, flagged with a note giving the range. The printed summary therefore differs for simulations run with time-varying effort. -
MizerSimmethod forplotDiet()introduced in version 3.0 simply plotted the diet at the initial time of the simulation. NowplotDiet()for aMizerSimaccepts atime_rangeargument. The diet is now computed from the simulated abundances at the requested times, defaulting to the final saved step, rather than the initial one (#357). -
Other components and
t_save.project()was advancing the abundances of other components (set viasetComponent()) only once per saved time step instead of once perdtstep. They are now integrated with the samedtas the consumer and resource spectra, so results for models with other components no longer depend ont_save. -
Time-varying effort in
getRDI(),getRDD(),getFlux(). On aMizerSimobject these now use the simulated time-varying effort rather than the initial effort, so they change for simulations with varying effort (#370). -
plotCDF()/plotlyCDF()bin placement. Each cumulative value is now plotted at its bin’s upper edge, correcting a one-bin offset. The curves shift by one bin compared with 3.0 (#383). -
distanceMaxRelRDI(). Now returnsInfinstead ofNaNwhen a previous RDI is zero, soprojectToSteady()no longer mistakes aNaNdistance for convergence. Convergence behaviour can therefore differ in edge cases.
Second-order methods advance the resource at the midpoint
If you use project() with
method = "predictor_corrector" (or the new
method = "tr_bdf2"), the resource and the other components
are now advanced with midpoint rates rather than the start-of-step
value, so that they reach the same second-order accuracy in time as the
consumer spectra. Results from these methods therefore differ slightly
from 3.0. The default method = "euler" and the steady
states are unchanged.
Opting in to the second-order-in-size scheme
3.1 adds an optional, experimental second-order-accurate
finite-volume scheme in the size variable, controlled by the new
second_order_w slot. It is off by default,
so default results are byte-identical to 3.0. If you switch it on (via
second_order_w()<- or the second_order_w
argument of the new...Params() constructors),
size-integrated diagnostics and the resource spectrum shift by \(O(\Delta w)\), so a calibrated model may
need recalibrating. See ?second_order_w and the “Numerical
Details” vignette.
Upgrading from mizer 2.5.4 to 3.0
Version 3.0 is a large release. Most new capabilities are additive and off by default, but there are several renamed arguments, deprecations and behavioural changes that can affect existing code.
Renamed arguments and changed defaults (breaking changes)
-
First argument of
plotBiomass(),plotYield(),plotYieldGear()(and theirMizerSimmethods andplotly*wrappers) is renamed fromsimtoobject, for consistency with the other plot generics. Calls that passed the simulation by name,plotBiomass(sim = my_sim), must becomeplotBiomass(object = my_sim). Positional calls are unaffected. -
plotBiomassObservedVsModel()/plotlyBiomassObservedVsModel()now default toratio = FALSEfor all object types. Calls that relied on the previous ratio plot must setratio = TRUEexplicitly. -
plotDiet()no longer accepts atime_rangeargument. Remove it from your calls. (In 3.1 atime_rangeargument returns for theMizerSimmethod — see above.) -
Dimnames of
getMort()andgetPredRate()arrays are nowspandw(matchinggetFMort()and the other rate getters). Code that referred to the old dimnames by name must be updated.
Rate getters return classed array objects
Functions that return arrays of the form (species × size), (time ×
species) or (time × species × size) now attach extra attributes and an
S3 class (ArraySpeciesBySize,
ArrayTimeBySpecies or
ArrayTimeBySpeciesBySize). The numeric values and ordinary
matrix behaviour (arithmetic, subsetting) are unchanged, but the extra
class and attributes mean that a strict comparison such as
identical(getMort(params), old_value) can now report a
difference where the numbers agree. Use unclass(), or
compare with all.equal() on the values, if you need to
ignore the class. These objects also carry print(),
summary(), plot() and
as.data.frame() methods, so printing them looks different
from a bare matrix.
setInitialValues() is deprecated
setInitialValues() is deprecated. Replace
params <- setInitialValues(params, sim)with
params <- finalParams(sim)or, when averaging over a time range, with
getParams(sim, time_range, geometric_mean). This reflects a
shift in interpretation: a MizerParams object now
represents not just the model specification but also its current state
(the abundances), which can be extracted from a simulation with
getParams(), finalParams() and
initialParams().
Growth can no longer be negative
Growth is now forced to be non-negative, preventing unphysical shrinkage. In any model where the energy available for growth used to go negative (for example a strongly food-limited large individual), growth is now clamped at zero instead, so projected size spectra can differ from 2.5.4. No warning is issued when growth stops at or after the maturity size.
project() timing and effort handling
-
Inherited
dtandmethod. Whenproject()is called on an existingMizerSimobject,dtandmethodnow default to the values stored in the simulation’s newsim_paramsslot. If you pass values that differ from the stored ones, a warning is issued. To use different settings deliberately, pass them explicitly and expect the warning. -
t_max/t_savewith an effort array. These arguments are now respected even when an effort array is supplied (#231). Witht_maxthe simulation extends beyond the times in the effort array using the last known effort; witht_savethe save frequency is controlled independently, interpolating effort as needed. Simulations that previously derived their length or save times solely from the effort array may now produce a different set of saved steps. -
State at
t_maxalways saved.project()now warns whent_maxis not a multiple oft_saveand ensures the state att_maxis saved even if the final interval is shorter thant_save(#341). The returned simulation may therefore contain one extra saved time step compared with 3.0.
plot() and summary() are now S3
methods
The plot() and summary() methods for
MizerParams, MizerSim and the mizer array
classes are now registered as S3 methods rather than S4 methods, so
plot() and summary() stay plain S3 generics
when mizer is loaded. This avoids interfering with S4 dispatch in other
packages, but code that relied on plot/summary
being S4 generics (for example via selectMethod() or
getMethod()) needs adjusting.
Bug fixes that change results
-
getMeanMaxWeight()now applies the species selector to the denominator as well, so its values change when a subset of species is selected. -
plotSpectra()axis limits. It no longer forces the y-axis lower limit to1e-20(it auto-scales to the data) and, whenresource = FALSE, it usesmin(params@w)rather thanmin(params@w) / 100as the default lower size limit. Plots therefore look different. -
getFMort()on aMizerSimwas silently dropping the component names fromn_other, breaking rate functions that accessn_otherby name (e.g.n_other[["resource"]]); it now preserves them. -
getFMort.MizerSim()now passes the time argumenttto user-defined fishing-mortality functions, so a time-dependent fishing function now sees the correct time.
Predation diffusion is available but off by default
3.0 adds a diffusion term to the growth dynamics, controlled by the
new use_predation_diffusion slot. It defaults to
FALSE, preserving the behaviour of earlier mizer, so
existing models are unchanged unless you switch it on with
use_predation_diffusion(params) <- TRUE. Likewise the
new species parameters z_ext, d,
E_ext and D_ext for external mortality,
encounter and diffusion all default to values that leave the model
unchanged.
