Give each species parameter default a single home#458
Merged
Conversation
A default for a species parameter is now set by the rate setter that uses it. `species_params.data.frame()` only sets defaults for parameters that no single rate setter owns: those read by several setters (`n`), used only when projecting (`alpha`), needed to build the size grid (`w_min`, `w_max`), needed for the length-weight conversion (`a`, `b`), or used only for reporting (`is_background`). The defaults for `p`, `z_ext`, `d`, `E_ext`, `D_ext` and `interaction_resource` are therefore removed from the central table. They were already being set by `setMetabolicRate()`, `setExtMort()`, `setExtEncounter()`, `setExtDiffusion()` and `setInteraction()`, which need them anyway because the rate setters can be called directly, without going through `setParams()` and hence without `validSpeciesParams()`. Built models are unchanged, because `setParams()` calls every rate setter and so each deleted default is immediately re-supplied by its owner. But `validSpeciesParams()` applied to a bare species parameter data frame now returns fewer columns, which is a documented change. Removing the central `p = n` promotes `setMetabolicRate()`'s own `p` default from shadowed to live, so it is corrected from `3/4` to `n` to keep the effective default the same. The two had silently disagreed whenever `n != 3/4`, but the central one always ran first and won. Also removes the message in `setInteraction()`, which was dead while `interaction_resource` was set centrally and would otherwise now fire on every model build, and the unreachable `a`/`b` defaults in `plot_growth_curves()`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QZop1EdWQNm9SXGCqwWg8k
The entry claimed `setMetabolicRate()` is the only place that sets `p` and that `p = n` is the value models have been getting all along. Both are wrong: `newMultispeciesParams()` has its own `p` argument, default `0.7`, which it injects into the species parameter table before validation, so it preempts both the `validSpeciesParams()` and `setMetabolicRate()` defaults. Models built in the usual way get `p = 0.7`, not `p = n`. The claim that no model changes is unaffected and still holds. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QZop1EdWQNm9SXGCqwWg8k
The argument never had any effect on a `MizerParams` object. It is applied with `set_species_param_default()`, which only creates a missing column or fills in NAs and never overwrites, and every constructed `MizerParams` already has a non-NA `p` column because `newMultispeciesParams()` injects its own `p` argument into the species parameter table before validation. So the condition the argument was documented for -- "if the exponent is not specified in a `p` column" -- is unreachable, and the argument was silently ignored. Deprecate it in favour of setting the species parameter directly with `species_params(params)$p <- value`, which triggers `setParams()` and does what was meant. This also fits the rest of the family: `setSearchVolume()` has no `q` argument and `setMaxIntakeRate()` has no `n` argument. What the argument does is unchanged while it is deprecated; it now warns. The `p` argument of `newMultispeciesParams()` is a separate argument, is not forwarded to `setMetabolicRate()`, and is unaffected -- it is now documented explicitly there so that it does not inherit the deprecation badge, and is excluded from the arguments `setParams()` advertises in its dots. Closes #459 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QZop1EdWQNm9SXGCqwWg8k
Add a `species-param-defaults` skill recording the rule that #458 implements: a default lives with the rate setter that reads the parameter, and only parameters that no single rate setter owns are defaulted centrally in `species_params.data.frame()`. The skill deliberately does not repeat the list of central parameters or the five reasons for being on it; those live in the "Where defaults live" section of the `default_parameters` vignette, and the skill points there so the two cannot drift apart. What it adds is the part a contributor needs and a user does not: decide by consumption rather than by tidiness; a setter-local default is a precondition guard rather than redundancy, because the rate setters are public API called without `setParams()`, and removing one fails silently; two homes for one default go divergent, as `p` did; the `given_species_params` argument rule; and how to prove a move is numerically inert with a golden-model diff. AGENTS.md gains the pointer to the skill plus the one fact that is definitional rather than procedural: `given_species_params` holds the defaults of function arguments that set species parameters, even when the user did not override them. The slot's name invites the opposite conclusion, and a reader can reach it without doing any work on defaults at all. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QZop1EdWQNm9SXGCqwWg8k
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Every species parameter default now has exactly one home, and which home is decided by what consumes the parameter. Two commits, same principle pulling in opposite directions:
aandb(0b5b661) are consumed by the length-weight conversion itself —l2w()/w2l()are called fromcheck_and_convert_species_params()insidespecies_params.data.frame(). Their defaults move intospecies_paramsrather than being applied ad-hoc insidel2w()/w2l().p,z_ext,d,E_ext,D_ext,interaction_resource(c610222) are each read by exactly one rate setter. Their defaults move out of the central table to that setter — where they already were, duplicated.Which parameters stay central
A parameter is defaulted by
validSpeciesParams()only when no single rate setter owns it, which happens for five reasons:n(six of them:setExtDiffusion,setExtEncounter,setExtMort,setMaxIntakeRate,setReproduction,setSearchVolume);w_mat,w_infalphaw_min,w_maxa,bis_backgroundEverything else belongs to its setter:
p/ktosetMetabolicRate(),z0/z_ext/dtosetExtMort(),E_exttosetExtEncounter(),D_exttosetExtDiffusion(),interaction_resourcetosetInteraction(),q/gammatosetSearchVolume(),erepro/m/w_mat25/R_maxtosetReproduction(),beta/sigmatosetPredKernel().The setter-local defaults are not redundancy: the rate setters are public API that can be called directly, without
setParams()and hence withoutvalidSpeciesParams(), so each setter has to supply what it needs on its own. Tests already relied on this (e.g.test-setExtMort.RNULLsz_ext/dand requiressetExtMort()to restore them).The
pdefaultThree places set
p, with three different values:newMultispeciesParams()'s ownpargument, default0.7, injected into the species parameter table at newMultispeciesParams.R#L179-L180 before validation;species_params.data.frame()'sp = n;setMetabolicRate()'sp = 3/4.(1) preempts both others, so it is
p = 0.7— notp = n— that models built in the usual way have been getting. (2) applied only whenvalidSpeciesParams()was called directly on a bare data frame, and it shadowed (3).This PR removes (2). That promotes (3) from shadowed to live, so it is corrected from
3/4tonfor consistency with the exponent it tracks. (1) is untouched and still wins fornewMultispeciesParams(), which is why no model changes.The
pargument ofsetMetabolicRate()(deprecated here)There is a fourth would-be home:
setMetabolicRate()'s ownpargument. It never had any effect on aMizerParamsobject, because it is applied withset_species_param_default()— which only fills a missing orNAcolumn and never overwrites — and (1) guarantees the column is always already there. The condition it was documented for, "if the exponent is not specified in apcolumn", is unreachable. It was silently ignored.It is now deprecated in favour of
species_params(params)$p <- value, which triggerssetParams()and does what was meant. This also makes the family consistent:setSearchVolume()has noqargument andsetMaxIntakeRate()has nonargument. What the argument does is unchanged while deprecated; it just warns now.newMultispeciesParams()'spis a different argument, is not forwarded tosetMetabolicRate(), and still works. It is now documented explicitly there so it does not inherit the deprecation badge, and is excluded from the argumentssetParams()advertises in its dots.Closes #459.
Behaviour
Built models are unchanged —
setParams()calls every rate setter, so each deleted default is immediately re-supplied by its owner. Verified with a golden-model diff ofNS_paramsacross the change: nospecies_paramscolumn lost, and no numeric change tosearch_vol,intake_max,metab,mu_b,psi,maturity,ext_encounter,ext_diffusion,initial_norinteraction.User-visible change:
validSpeciesParams()applied to a bare species parameter data frame now returns fewer columns; the setter-owned ones appear once the model is built. Its roxygen previously documented returningn,p,z_ext,d,E_ext,D_extandinteraction_resource, and has been rewritten.Also
interaction_resourcenote insetInteraction(). It was dead while the column was set centrally and would otherwise have fired on every model build; "all species feed on the resource" is the unremarkable default.a = 0.004/b = 3defaults inplot_growth_curves(), which conflicted with the centrala = 0.01.Tests
test-validSpeciesParams.R: asserts the setter-owned columns are absent from a barevalidSpeciesParams()result but present on a built model; guards the no-maximum-size case.test-setMetabolicRate.R: pinsp == nrather than a hardcoded3/4, and that the construction and standalone-setter paths agree.test-setExtEncounter.R/test-setExtDiffusion.R: new standalone-setter tests forE_ext/D_extrestoration.test-setMetabolicRate.R: thepargument warns; setting the species parameter works;newMultispeciesParams(sp, p =)still works and does not warn. The existing test that pinned the argument's fill-only semantics is kept (they are unchanged) and renamed.Full suite green apart from
test-plots.R:501, which fails identically onmasterand is annotated in-source as machine-dependent.🤖 Generated with Claude Code
https://claude.ai/code/session_01QZop1EdWQNm9SXGCqwWg8k