Skip to content

w_min is missing from given_species_params, so min_w is silently lost on a round-trip #460

Description

@gustavdelius

Summary

min_w is an argument of newMultispeciesParams()/emptyParams() and it sets the w_min species parameter. But w_min never reaches given_species_params, so any operation that rebuilds the species parameters from the given ones discards the user's value and silently substitutes the default 0.001.

The principle this breaks: a species parameter that is an argument to a function belongs in given_species_params, even when the user does not override the argument's default. n and p are handled that way; w_min is not.

Reproduction

sp <- data.frame(species = c("a", "b"), w_inf = c(100, 200))
params <- newMultispeciesParams(sp, min_w = 1e-4)

species_params(params)$w_min[1]                      # 1e-04
"w_min" %in% names(given_species_params(params))     # FALSE   <- the bug

# any round-trip through given_species_params<- rebuilds the table
given_species_params(params)$alpha <- 0.7

species_params(params)$w_min[1]                      # 0.001   <- silently changed

The egg size changes by a factor of ten with no warning, and w_min_idx moves from 1 to 16.

Why

emptyParams() snapshots the given species parameters before it applies the min_w argument:

https://github.com/sizespectrum/mizer/blob/master/R/MizerParams-class.R#L551-L556

given_species_params <- validGivenSpeciesParams(species_params)   # line 551

## Set defaults ----
if (is.na(min_w_pp)) min_w_pp <- 1e-12
species_params <- set_species_param_default(species_params, "w_min", min_w)   # line 555

So w_min is added to species_params but never to given_species_params. given_species_params<- then rebuilds with

params@given_species_params <- value
params@species_params <- validSpeciesParams(value)

and validSpeciesParams() applies its own hardcoded w_min = 0.001.

Contrast newMultispeciesParams(), which gets this right for its n and p arguments by injecting them into the data frame before emptyParams() is called:

https://github.com/sizespectrum/mizer/blob/master/R/newMultispeciesParams.R#L179-L180

Why it is not always visible

validParams() has a guard that raises w_min when it drops below the weight grid. When min_w is larger than 0.001 that guard fires and restores the value — at the cost of a spurious warning on a round-trip that changed nothing about sizes:

params <- newMultispeciesParams(sp, min_w = 0.01)
given_species_params(params)$alpha <- 0.7
#> Warning: The minimum weight of some species was smaller than the minimum weight
#> of the weight grid in the model: a, b. I have increased it to 0.01. ...

When min_w is smaller than 0.001, the reset value sits above the grid minimum, the guard never fires, and the change is silent. That is the case in the reproduction above.

So there are two symptoms: silent loss of a small min_w, and a spurious warning for a large one.

Suggested fix

Apply the min_w argument before taking the snapshot, i.e. move line 555 above line 551 in emptyParams(), so that w_min lands in given_species_params the way n and p do.

Worth checking while doing so: validGivenSpeciesParams() contains a correction that lowers w_min when it is not smaller than w_mat (w_min[wrong] <- pmin(0.001, w_mat[wrong] / 10)). Once w_min is present at snapshot time that correction will start applying to it, which is probably desirable but is a behaviour change and should get a test.

A regression test should assert that w_min survives a given_species_params<- round-trip for min_w both above and below 0.001.

Related

  • Give each species parameter default a single home #458 — gives each species parameter default a single home. This is the same family of problem (w_min has a default in emptyParams() via min_w and another in species_params.data.frame()), but the PR does not touch it: it deliberately leaves the emptyParams() w_min default alone, since that one has to run before validSpeciesParams() or the min_w argument would be ignored entirely.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QZop1EdWQNm9SXGCqwWg8k

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions