Skip to content

Give the resource a weight-length relationship - #539

Merged
gustavdelius merged 1 commit into
array-type-attributefrom
resource-length-params
Aug 16, 2026
Merged

Give the resource a weight-length relationship#539
gustavdelius merged 1 commit into
array-type-attributefrom
resource-length-params

Conversation

@gustavdelius

Copy link
Copy Markdown
Member

Stacked on #538 — review that one first; this PR's diff is against array-type-attribute.

Summary

plotSpectra(params, size_axis = "l") used to drop the resource silently — 79 rows on the weight axis, 0 on the length axis, no message — because the length conversion needs an allometric weight-length relationship and only the species had one.

resource_params() now carries a and b, defaulting to the equivalent spherical diameter of an organism with the density of water, $w = \frac{\pi}{6}l^3$, i.e. a = pi/6 ≈ 0.524, b = 3. ESD is the standard convention in plankton ecology precisely because it is geometric rather than taxonomic, so it degrades gracefully across a composite of many taxa. On a mizer grid it gives sensible sizes throughout:

w (g) ESD plausible organism
1e-12 1.2 µm bacterium
1e-6 124 µm ciliate / small copepod
1e-3 1.2 mm copepod
9.8 (w_pp_cutoff) 2.7 cm macrozooplankton

The resource therefore appears on length-based spectra, and the resource array classes gain size_axis and llim, animate() included — it used to raise "a length axis is not available for resource arrays".

The convention caveat

The resource sits on the length axis at its own convention: a fish of a given weight is about 3.7× longer than a sphere of that weight. Two things about that:

  • It is real biology, not an artefact. A 1 mg copepod really is shorter than a 1 mg fish larva, so the step at the resource–consumer boundary is information.
  • Because both conventions have b = 3, the change is a pure translation on a log-length axis: the resource curve keeps its shape and slope.

It is also not a new kind of compromise — a length axis is already per-species, since each species converts with its own a, b.

Design

The parameters feed none of the rates, so they are deliberately not arguments of setResource(). Instead:

  • setResource() fills them in as defaults, so every newly built model shows them in resource_params() and users can change them there;
  • they are also defaulted at the point of use (resource_length_params()), so a model saved before they existed needs no upgrade — and repair_params() and validation_key() stay untouched, which would otherwise have meant adding resource_params to the fingerprint of every object.
  • resource_params<-() validates them when present.

The one shared change is plot_length_params(), which replaces the inline species_params lookup in convert_plot_size_axis() and the Jacobian in convert_plot_density_axis(). It returns a/b per row — from the species, from the resource, or NA for anything else — so both the coordinate conversion and the density Jacobian handle the resource through one place.

Testing

Full suite: 4288 passing, 0 failures. New tests cover the default and the fallback for old objects, validation, the ESD sanity check (µm at 1e-12 g, mm at 1e-3 g, the 3.741 fish/ESD ratio), the resource on a length axis with the Jacobian and llim, and the resource joining a length-axis plotSpectra(). One existing test asserted that both Resource and Total are hidden on a length axis; it now asserts that Resource appears and Total still does not — the latter is the next PR.

🤖 Generated with Claude Code

`plotSpectra(params, size_axis = "l")` used to drop the resource
silently, because the length conversion needs an allometric
weight-length relationship and only the species had one.

`resource_params()` now carries `a` and `b`, defaulting to the
equivalent spherical diameter of an organism with the density of water,
`a = pi/6` and `b = 3`. That is the convention plankton ecology uses for
a composite of many taxa, and on a mizer grid it puts the smallest
resource sizes below a micrometre and a milligram organism at about a
millimetre.

The resource therefore appears on length-based spectra, and the resource
array classes gain `size_axis` and `llim`, `animate()` included.

The parameters feed none of the rates, so they are not arguments of
`setResource()`; it fills them in as defaults so that
`resource_params()` shows them, and they are also defaulted at the point
of use so that models saved before they existed need no upgrade.

Note that the resource then sits on the length axis at its own
convention: a fish of a given weight is about 3.7 times longer than a
sphere of that weight. That difference is real rather than an artefact —
a 1 mg copepod really is shorter than a 1 mg fish larva — but it does
mean the resource and the species are measured differently.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant