Skip to content

Proposal: Introduce feeding_level() accessor and feeding_level<-() setter to tune feeding levels #536

Description

@gustavdelius

Summary

Following the unified treatment of extrinsic density dependencies proposed in #190, mizer has harmonised:

  1. Resource density dependence: resource_level() / resource_level<- and setResource(), tuning carrying capacity $c(w)$ vs regeneration rate $r(w)$.
  2. Reproduction density dependence: reproduction_level() / reproduction_level<- and setBevertonHolt(), tuning maximum recruitment $R_{\max}$ vs reproductive efficiency $e_{\text{repro}}$.

The third density dependence identified in #190 is feeding level (Type II functional response governed by maximum consumption rate $h$ and search volume $\gamma$). This proposal outlines the design for a feeding_level() accessor and feeding_level<- replacement setter (or setFeedingLevel()).


Motivation

The feeding level $f_i(w) = \frac{E_i(w)}{E_i(w) + h_i w^n}$ dictates where an organism operates on its Holling type II functional response curve:

  • At $f \approx 1$ (near satiation), feeding and growth are largely insensitive to fluctuations in prey abundance.
  • At low $f \ll 1$, feeding is prey-limited and proportional to encounter rate.

In model construction (newCommunityParams(), newTraitParams()), a default parameter f0 is used to determine the search volume constant $\gamma$. However, once a model is constructed or calibrated, adjusting the feeding level to explore how trophic sensitivity affects ecosystem dynamics currently requires manual recalculation of search volume or maximum intake rate.


Mathematical Balancing Options for feeding_level<-

Suppose we wish to change the feeding level from $f_i(w)$ to a new target $f_i^\ast(w)$ (or a species-scalar target $f_{0,i}^\ast$). Two main balancing approaches are possible:

Option 1: Preserve Growth ($g(w)$ invariant)

To preserve the steady-state growth rate $g_i(w) = (1 - \text{def}) \alpha f_i(w) h_i w^n - \text{metab}_i(w)$, the realized consumption rate $f_i(w) h_i w^n$ must remain constant:
$$f_i^\ast(w) h_i^\ast = f_i(w) h_i \implies h_i^\ast(w) = h_i(w) \frac{f_i(w)}{f_i^\ast(w)}$$
To achieve the new feeding level $f_i^\ast(w)$ with the new $h_i^\ast$, the encounter rate must satisfy:
$$\frac{E_i^\ast(w)}{E_i^\ast(w) + h_i^\ast(w) w^n} = f_i^\ast(w) \implies E_i^\ast(w) = \frac{f_i^\ast(w)}{1 - f_i^\ast(w)} h_i^\ast(w) w^n = \frac{f_i(w)}{1 - f_i^\ast(w)} h_i(w) w^n$$
Since $E_i(w) = \frac{f_i(w)}{1 - f_i(w)} h_i(w) w^n$, the search volume $\gamma_i(w)$ is scaled by:
$$\gamma_i^\ast(w) = \gamma_i(w) \frac{1 - f_i(w)}{1 - f_i^\ast(w)}$$

  • Properties: Growth rates and the steady-state size spectrum are preserved; feeding resilience and encounter rates are modified. Predation mortality on prey at steady state remains invariant because $f^\ast h^\ast = f h$, though the response to non-steady perturbations changes.

Option 2: Preserve Maximum Intake ($h$ invariant)

Keep $h_i$ fixed and adjust only the search volume $\gamma_i(w)$:
$$E_i^\ast(w) = \frac{f_i^\ast(w)}{1 - f_i^\ast(w)} h_i w^n \implies \gamma_i^\ast(w) = \gamma_i(w) \frac{f_i^\ast(w) / (1 - f_i^\ast(w))}{f_i(w) / (1 - f_i(w))}$$

  • Properties: Keeps physiological $h$ fixed, but changes realized growth and predation rates. Requires running steady() or matchGrowth() afterwards to settle onto a new steady state.

Proposed API

# Query current feeding level
feeding_level(params)

# Set new target feeding level (scalar per species or size-dependent)
feeding_level(params) <- 0.6

# Or via explicit function with options:
setFeedingLevel(params, feeding_level = 0.6, preserve = c("growth", "intake_max"))

Design Questions

  1. Should feeding_level<- preserve growth by default (preserve = "growth") or preserve maximum intake (preserve = "intake_max")?
  2. How should species-scalar inputs be mapped across the size spectrum when $f_i(w)$ varies with size? (e.g. scale relative to mean feeding level, or feeding level at maturation size $w_{\text{mat}}$).
  3. Relationship with getFeedingLevel(): Should getFeedingLevel() remain the instantaneous rate calculator while feeding_level() provides the accessor/setter interface, or should getFeedingLevel() eventually follow the standard deprecation path?

Metadata

Metadata

Assignees

No one assigned

    Labels

    discussionAn idea that needs discussion before becoming a proposalenhancementNew feature requests or suggestions for enhancement of existing features

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions