API for the scaling_functions module#

The models.animal.scaling_functions module contains a set of functions containing scaling equations” (relationships between body-mass and a trait) required by the broader animal module

To Do: - streamline units of scaling functions [kg]->[kg] etc

Functions:

H_i_j(h_pred_0, M_ref, M_i_t, b_pred, prey_mass)

Handling time of prey cohort j by cohort i.

H_i_k(h_herb_0, M_ref, M_i_t, b_herb)

Handling time of plant resource k by cohort i.

activity_window(metabolic_type, temperature, ...)

Proportion of the timestep suitable for a cohort to be active.

alpha_i_j(alpha_0_pred, mass, w_bar_i_j)

Rate at which an individual predator searches its environment and kills prey.

alpha_i_k(alpha_0_herb, mass)

Effective rate at which an individual herbivore searches its environment.

background_mortality(u_bg)

Constant background rate of wastebasket mortality.

bfs_territory(centroid_key, ...)

Performs breadth-first search (BFS) to generate a list of territory cells.

biomass_density_to_individuals(...)

Convert a biomass density to a total individual count.

damuths_law(mass, terms)

The function set initial population densities .

heterotroph_normalization_factor(...)

Normalization factor scaling all functional groups to a fixed biomass budget.

juvenile_dispersal_speed(current_mass, ...)

Dispersal speed of cohorts during diffusive natal dispersal event [km/month].

k_i_j(alpha_i_j, N_i_t, intersection_area, ...)

Potential number of prey items eaten off j by i.

k_i_k(alpha_i_k, B_k_t, A_cell)

The potential biomass (g) of plant k eaten by cohort i, per day.

metabolic_rate(mass, temperature, terms, ...)

Calculates metabolic rate in grams of body mass per day.

p_above_t_max(temperature, ...)

Proportion of the day during which temperature exceeds the upper critical limit.

p_below_t_min(temperature, ...)

Proportion of the day during which temperature is below the lower limit.

prey_group_selection(diet_type, mass, terms, ...)

Selects prey groups available to a consumer based on diet and available groups.

raw_biomass_density_kg_m2(functional_group, ...)

Raw biomass density for a functional group before normalization.

senescence_mortality(lambda_se, ...)

Age-based mortality.

starvation_mortality(lambda_max, J_st, ...)

Mortality from body-mass loss.

t_max_crit_ectotherm(annual_mean_temp, ...)

Upper critical temperature for a terrestrial ectothermic functional group.

t_min_crit_ectotherm(t_max_crit, t_opt)

Lower critical temperature for a terrestrial ectothermic functional group.

t_opt_ectotherm(annual_mean_temp, ...)

Optimal activity temperature for a terrestrial ectothermic functional group.

territory_size(mass_kg, terms)

Allometric scaling of territory size from body mass.

theta_opt_i(theta_opt_min_f, theta_opt_f, ...)

Optimum predator-prey mass ratio.

w_bar_i_j(mass_predator, mass_prey, ...)

The probability of successfully capturing a prey item.

virtual_ecosystem.models.animal.scaling_functions.H_i_j(h_pred_0: float, M_ref: float, M_i_t: float, b_pred: float, prey_mass: float) float[source]#

Handling time of prey cohort j by cohort i.

Time (days) for an individual of cohort i to handle 1 individual of cohort j.

TODO: update name

Madingley

Parameters:
  • h_pred_0 – Time that it would take a predator of body mass equal to the reference mass, to handle a prey individual of body mass equal to one gram.

  • M_ref – Reference body mass.

  • M_i_t – Current predator mass.

  • b_pred – Exponent of the power-law function relating the handling time of prey to predator mass.

  • prey_mass – the mass of prey being handled.

Returns:

A float of the handling time (days).

virtual_ecosystem.models.animal.scaling_functions.H_i_k(h_herb_0: float, M_ref: float, M_i_t: float, b_herb: float) float[source]#

Handling time of plant resource k by cohort i.

Time (days) for an individual of cohort i to handle 1 gram of plant resource.

TODO: update name

Madingley

Parameters:
  • h_herb_0 – Time in days that it would take a herbivore of mass = M_ref to handle 1g of autotroph mass.

  • M_ref – Reference body mass.

  • M_i_t – Current herbivore mass

  • b_herb – Exponent of the power-law function relating the handling time of autotroph matter to herbivore mass

Returns:

A float of the handling time (days).

virtual_ecosystem.models.animal.scaling_functions.activity_window(metabolic_type: MetabolicType, temperature: float, diurnal_temp_range: float, annual_mean_temp: float, annual_temp_sd: float, t_opt: float | None = None, t_max_crit: float | None = None, t_min_crit: float | None = None, constants: AnimalConstants = AnimalConstants()) float[source]#

Proportion of the timestep suitable for a cohort to be active.

Implements Madingley eqs. 41-47:

  • Endotherms are active for the full timestep (eq. 41).

  • Terrestrial ectotherms are limited to the fraction of the day within their thermal tolerance window, derived from the diurnal temperature cycle and climatological statistics (eq. 42).

\[\begin{split}\\varsigma_{f(t)} = \\begin{cases} 1 & \\text{if } f \\text{ is endotherm} \\\\ 1 - (p_{Above,f} + p_{Below,f}) & \\text{if } f \\text{ is ectotherm} \\end{cases}\end{split}\]

The result is clamped to [0, 1] to guard against floating-point cases where p_above + p_below marginally exceeds 1.

If t_opt, t_max_crit, and t_min_crit are all provided they are used directly, bypassing the toy-parameter derivation from climate statistics. If any are None the full derivation from annual_mean_temp and annual_temp_sd is used instead.

Parameters:
  • metabolic_type – Whether the cohort is endothermic or ectothermic.

  • temperature – Monthly mean ambient temperature $T_C$ [°C].

  • diurnal_temp_range – Monthly mean diurnal temperature range $\Delta T_{Diurnal}^C$ [°C].

  • annual_mean_temp – Annual mean ambient temperature $T_{Annual}^C$ [°C].

  • annual_temp_sd – Standard deviation of monthly temperatures across the climatological year $\sigma_{T_{Annual}^C}$ [°C].

  • t_opt – Optional optimal activity temperature [°C]. If provided alongside t_max_crit and t_min_crit, overrides the toy-parameter derivation.

  • t_max_crit – Optional upper critical temperature [°C]. See t_opt.

  • t_min_crit – Optional lower critical temperature [°C]. See t_opt.

  • constants – Animal constants supplying the four activity window parameters, used only when t_opt, t_max_crit, and t_min_crit are not all provided.

Returns:

Activity window fraction in [0, 1].

virtual_ecosystem.models.animal.scaling_functions.alpha_i_j(alpha_0_pred: float, mass: float, w_bar_i_j: float) float[source]#

Rate at which an individual predator searches its environment and kills prey.

This is linear scaling of herbivore search times with current body mass.

TODO: update name

Madingley

Parameters:
  • alpha_0_pred – Constant describing effective rate per unit body mass at which any predator searches its environment in m2/(day*g).

  • mass – The current body mass of the foraging herbivore.

  • w_bar_i_j – The probability of successfully capturing a prey item.

Returns:

A float of the effective search rate in [m2/day]

virtual_ecosystem.models.animal.scaling_functions.alpha_i_k(alpha_0_herb: float, mass: float) float[source]#

Effective rate at which an individual herbivore searches its environment.

This is linear scaling of herbivore search times with current body mass.

TODO: Update name

Madingley

Parameters:
  • alpha_0_herb – Effective rate per unit body mass at which a herbivore searches its environment in m2/(day*g).

  • mass – The current body mass of the foraging herbivore in g.

Returns:

A float of the effective search rate in [m2/day].

virtual_ecosystem.models.animal.scaling_functions.background_mortality(u_bg: float) float[source]#

Constant background rate of wastebasket mortality.

This function does nothing but return a constant at the moment. I am leaving it in so there is a clear way to alter the assumptions about background mortality as we move into testing and validation.

Madingley

Parameters:

u_bg – The constant of background mortality [day^-1].

Returns:

The background rate of mortality faced by a cohort [day^-1].

virtual_ecosystem.models.animal.scaling_functions.bfs_territory(centroid_key: int, target_cell_number: int, cell_nx: int, cell_ny: int) list[int][source]#

Performs breadth-first search (BFS) to generate a list of territory cells.

BFS does some slightly weird stuff on a grid of squares but behaves properly on a graph. As we are talking about moving to a graph anyway, I can leave it like this and make adjustments for diagonals if we decide to stay with squares/cells.

TODO: Revise for diagonals if we stay on grid squares/cells. TODO: might be able to save time with an ifelse for small territories TODO: scaling territories is a temporary home while i rework territories TODO: replace pop with collections.deque

Parameters:
  • centroid_key – The community key anchoring the territory.

  • target_cell_number – The number of grid cells in the territory.

  • cell_nx – Number of cells along the x-axis.

  • cell_ny – Number of cells along the y-axis.

Returns:

A list of grid cell keys representing the territory.

virtual_ecosystem.models.animal.scaling_functions.biomass_density_to_individuals(biomass_density_kg_m2: float, adult_mass_kg: float, total_area_m2: float) int[source]#

Convert a biomass density to a total individual count.

A scaling-law-agnostic conversion used after the heterotroph normalization factor has been applied. Dividing normalized biomass density by adult mass gives individual density; multiplying by total area gives the headcount.

Parameters:
  • biomass_density_kg_m2 – Biomass density [kg m⁻²].

  • adult_mass_kg – Adult body mass of the functional group [kg].

  • total_area_m2 – Total simulation area [m²].

Returns:

Total number of individuals, rounded up to the nearest integer.

Raises:

ValueError – If adult_mass_kg is not positive.

virtual_ecosystem.models.animal.scaling_functions.damuths_law(mass: float, terms: tuple) float[source]#

The function set initial population densities .

Currently, this function just employs Damuth’s Law (Damuth 1987) for terrestrial herbivorous mammals. Later, it will be expanded to other types. Damuth assumes body mass in g and final density in indiv/km2.

Parameters:
  • mass – The body-mass [kg] of an AnimalCohort.

  • terms – The tuple of population density terms used, default to Damuth.

Returns:

The population density of that AnimalCohort [individuals/m2].

virtual_ecosystem.models.animal.scaling_functions.heterotroph_normalization_factor(functional_groups: list[FunctionalGroup], target_biomass_density_kg_m2: float, density_scaling_method: str) float[source]#

Normalization factor scaling all functional groups to a fixed biomass budget.

In Madingley, total heterotroph biomass density is constrained to a target value regardless of how many functional groups are defined. This function computes the single multiplicative factor applied uniformly to every functional group’s raw individual count so that the sum of normalized biomass densities equals target_biomass_density_kg_m2.

Each functional group’s share of the budget is proportional to its raw biomass density, whether derived from an empirical override or an allometric scaling law. The same factor is applied to all groups.

Parameters:
  • functional_groups – All functional groups in the simulation.

  • target_biomass_density_kg_m2 – Target total heterotroph biomass density [kg m⁻²].

  • density_scaling_method – Allometric scaling method ("madingley" or "damuth").

Returns:

Normalization factor (dimensionless).

Raises:

ValueError – If the sum of raw biomass densities across all functional groups is zero, indicating a degenerate configuration.

virtual_ecosystem.models.animal.scaling_functions.juvenile_dispersal_speed(current_mass: float, V_disp: float, M_disp_ref: float, o_disp: float) float[source]#

Dispersal speed of cohorts during diffusive natal dispersal event [km/month].

Madingley

Parameters:
  • current_mass – The mass of an individual of the cohort during the current time step [kg].

  • V_disp – Diffusive dispersal speed on an individual with reference body-mass.

  • M_disp_ref – A reference body-mass.

  • o_disp – The power-law exponent for the mass-dispersal speed scaling relationship.

Returns:

The dispersal speed of a juvenile cohort in km/month.

virtual_ecosystem.models.animal.scaling_functions.k_i_j(alpha_i_j: float, N_i_t: float, intersection_area: float, theta_i_j: float) float[source]#

Potential number of prey items eaten off j by i.

TODO: update name

Madingley

Parameters:
  • alpha_i_j – Rate at which an individual predator searches its environment and kills prey in m2/(day*g).

  • N_i_t – Number of consumer individuals.

  • intersection_area – The overlapping area between predator and prey territories in m2.

  • theta_i_j – The cumulative density of organisms with a mass lying within the same predator specific mass bin.

Returns:

Potential number of prey items eaten off j by i [integer number of individuals]

virtual_ecosystem.models.animal.scaling_functions.k_i_k(alpha_i_k: float, B_k_t: float, A_cell: float) float[source]#

The potential biomass (g) of plant k eaten by cohort i, per day.

TODO: update name

Madingley

Parameters:
  • alpha_i_k – Effective rate at which an individual herbivore searches its environment.

  • B_k_t – Plant resource bool biomass.

  • A_cell – The area of one cell [standard = 1 ha]

Returns:

A float of The potential biomass (g) of plant k eating by cohort i, per day [g/day]

virtual_ecosystem.models.animal.scaling_functions.metabolic_rate(mass: float, temperature: float, terms: dict, metabolic_type: MetabolicType, sigma_f_t: float, metabolic_scaling_coefficients: tuple[float, float] = AnimalConstants().metabolic_scaling_coefficients, boltzmann_constant: float = CoreConstants().boltzmann_constant) float[source]#

Calculates metabolic rate in grams of body mass per day.

This follows the Madingley implementation, assuming a power-law relationship with mass and an exponential relationship with temperature.

\[\Delta M_i^{metab} = E_S \left[ \varsigma_{f(t)} \cdot I_{0,f}^{FMR} \cdot e^{-E_A / k_B T^{K,body}} \cdot M_{i(t)}^{b_f^{FMR}} + (1 - \varsigma_{f(t)}) \cdot I_0^{BMR} \cdot e^{-E_A / k_B T^{K,body}} \cdot M_{i(t)}^{b^{BMR}} \right] \Delta t_d\]
Parameters:
  • mass – The body-mass [kg] of an AnimalCohort.

  • temperature – The temperature [Celsius] of the environment.

  • terms – The tuple of metabolic rate terms used.

  • metabolic_type – The metabolic type of the animal [ENDOTHERMIC or ECTOTHERMIC].

  • sigma_f_t – Activity window fraction in [0, 1].

  • metabolic_scaling_coefficients – A 2-tuple of - the energy-to- mass conversion constant and the aggregate activation energy of metabolic reactions.

  • boltzmann_constant – The Boltzmann constant ($k_B$)

Returns:

The metabolic rate of a single individual [kg/day].

virtual_ecosystem.models.animal.scaling_functions.p_above_t_max(temperature: float, diurnal_temp_range: float, t_max_crit: float) float[source]#

Proportion of the day during which temperature exceeds the upper critical limit.

Models the daily temperature cycle as a sine wave centred on the monthly mean temperature with amplitude diurnal_temp_range / 2. Returns the fraction of the period for which that cycle exceeds t_max_crit (Madingley eq. 43).

\[\begin{split}p_{Above,f} = \\frac{\\pi/2 - \\sin^{-1} \\left[\\text{clamp}\\left( \\frac{2(T_{\\max,f}^{crit} - T_C)}{\\Delta T_{Diurnal}^C}, -1, 1\\right)\\right]}{\\pi}\end{split}\]

The piecewise clamping ensures the arcsin receives a valid argument when the threshold lies entirely outside the daily temperature range, which is equivalent to the explicit if branches in the original Madingley formulation.

Parameters:
  • temperature – Monthly mean ambient temperature $T_C$ [°C].

  • diurnal_temp_range – Monthly mean diurnal temperature range $\Delta T_{Diurnal}^C$ [°C].

  • t_max_crit – Upper critical temperature $T_{\max,f}^{crit}$ [°C].

Returns:

Proportion of the day that is too hot for activity [0, 1].

virtual_ecosystem.models.animal.scaling_functions.p_below_t_min(temperature: float, diurnal_temp_range: float, t_min_crit: float) float[source]#

Proportion of the day during which temperature is below the lower limit.

Mirrors p_above_t_max() for the cold end of the activity window (Madingley eq. 44). The \(1 - {\\ldots}\) flip converts “proportion of the day above t_min_crit” into “proportion of the day below t_min_crit”.

\[\begin{split}p_{Below,f} = 1 - \\frac{\\pi/2 - \\sin^{-1} \\left[\\text{clamp}\\left( \\frac{2(T_{\\min,f}^{crit} - T_C)}{\\Delta T_{Diurnal}^C}, -1, 1\\right)\\right]}{\\pi}\end{split}\]
Parameters:
  • temperature – Monthly mean ambient temperature $T_C$ [°C].

  • diurnal_temp_range – Monthly mean diurnal temperature range $\Delta T_{Diurnal}^C$ [°C].

  • t_min_crit – Lower critical temperature $T_{\min,f}^{crit}$ [°C].

Returns:

Proportion of the day that is too cold for activity [0, 1].

virtual_ecosystem.models.animal.scaling_functions.prey_group_selection(diet_type: DietType, mass: float, terms: tuple, functional_groups: Sequence[FunctionalGroup]) dict[str, tuple[float, float]][source]#

Selects prey groups available to a consumer based on diet and available groups.

Parameters:
  • diet_type – Consumer’s DietType flag(s).

  • mass – Mass of the consumer (currently unused).

  • terms – Placeholder for mass-scaling logic.

  • functional_groups – All functional groups in the model.

Returns:

A dictionary mapping prey/resource group names to mass ranges.

virtual_ecosystem.models.animal.scaling_functions.raw_biomass_density_kg_m2(functional_group: FunctionalGroup, density_scaling_method: str) float[source]#

Raw biomass density for a functional group before normalization.

For functional groups with an empirical density override (density_individuals_m2 set in the CSV), biomass density is derived directly from that empirical value. For all other functional groups the appropriate allometric scaling law is used.

The returned value is in kg m⁻² and represents the functional group’s contribution to the heterotroph biomass budget before the cross-group normalization factor is applied.

Parameters:
  • functional_group – The functional group to evaluate.

  • density_scaling_method – The allometric scaling method to use for groups without an empirical density override. Must be "madingley" or "damuth".

Returns:

Raw biomass density [kg m⁻²].

Raises:

ValueError – If density_scaling_method is not recognised.

virtual_ecosystem.models.animal.scaling_functions.senescence_mortality(lambda_se: float, t_to_maturity: float, t_since_maturity: float) float[source]#

Age-based mortality.

Madingley describes the equation as exp(time_to_maturity/time_since_maturity) but I suspect this is an error and that it should be inverted. If, for example, it took 1000 days to reach maturity and the cohort had been mature for 1 day, then the instantaneous rate of senescence mortality would be lambda_se * exp(1000/1). This would also mean that the rate of senescence would decrease over time. Therefore, I have inverted the relationship below.

TODO: Check Madingley code for function implementation

Parameters:
  • lambda_se – The instantaneous rate of senescence mortality at point of maturity [day^-1].

  • t_to_maturity – The time it took the cohort to reach maturity [days].

  • t_since_maturity – The time elapsed since the cohort reached maturity [days].

Returns:

The rate of senescence mortality faced by an animal cohort [day^-1].

virtual_ecosystem.models.animal.scaling_functions.starvation_mortality(lambda_max: float, J_st: float, zeta_st: float, mass_current: float, mass_max: float) float[source]#

Mortality from body-mass loss.

There is a error in the madingley paper that does not follow their source code. The paper uses exp(k) instead of exp(-k).

Parameters:
  • lambda_max – The maximum possible instantaneous fractional starvation mortality rate. [day^-1]

  • J_st – Determines the inflection point of the logistic function describing ratio of the realised mortality rate to the maximum rate. [unitless]

  • zeta_st – The scaling of the logistic function describing the ratio of the realised mortality rate to the maximum rate. [unitless]

  • mass_current – The current mass of the animal cohort [kg].

  • mass_max – The maximum body mass ever achieved by individuals of this type [kg].

Returns:

The rate of mortality from starvation based on current body-mass. [day^-1]

virtual_ecosystem.models.animal.scaling_functions.t_max_crit_ectotherm(annual_mean_temp: float, annual_temp_sd: float, m_tol: float, c_tol: float) float[source]#

Upper critical temperature for a terrestrial ectothermic functional group.

Implements Madingley eq. 45:

\[\begin{split}T_{\\max,f}^{crit} = m_{tol,terrestrial} \\cdot \\sigma_{T_{Annual}^C} + c_{tol,terrestrial} + T_{Annual}^C\end{split}\]
Parameters:
  • annual_mean_temp – Annual mean ambient temperature $T_{Annual}^C$ [°C].

  • annual_temp_sd – Standard deviation of monthly temperatures across the climatological year $\sigma_{T_{Annual}^C}$ [°C].

  • m_tol – Slope of the variability-upper-critical-temperature relationship.

  • c_tol – Intercept of the variability-upper-critical-temperature relationship [°C].

Returns:

Upper critical temperature [°C].

virtual_ecosystem.models.animal.scaling_functions.t_min_crit_ectotherm(t_max_crit: float, t_opt: float) float[source]#

Lower critical temperature for a terrestrial ectothermic functional group.

Implements Madingley eq. 46:

\[\begin{split}T_{\\min,f}^{crit} = T_{opt,f} - 4 \\cdot \\frac{T_{\\max,f}^{crit} - T_{opt,f}}{12}\end{split}\]
Parameters:
  • t_max_crit – Upper critical temperature $T_{\max,f}^{crit}$ [°C].

  • t_opt – Optimal activity temperature $T_{opt,f}$ [°C].

Returns:

Lower critical temperature [°C].

virtual_ecosystem.models.animal.scaling_functions.t_opt_ectotherm(annual_mean_temp: float, annual_temp_sd: float, m_tsm: float, c_tsm: float) float[source]#

Optimal activity temperature for a terrestrial ectothermic functional group.

Implements Madingley eq. 47:

\[\begin{split}T_{opt} = m_{tsm} \\cdot \\sigma_{T_{Annual}^C} + c_{tsm} + T_{Annual}^C\end{split}\]
Parameters:
  • annual_mean_temp – Annual mean ambient temperature $T_{Annual}^C$ [°C].

  • annual_temp_sd – Standard deviation of monthly temperatures across the climatological year $\sigma_{T_{Annual}^C}$ [°C].

  • m_tsm – Slope of the variability-optimal temperature relationship.

  • c_tsm – Intercept of the variability-optimal temperature relationship [°C].

Returns:

Optimal activity temperature [°C].

virtual_ecosystem.models.animal.scaling_functions.territory_size(mass_kg: float, terms: tuple[float, float]) float[source]#

Allometric scaling of territory size from body mass.

TODO: Decide whether to use current mass or adult mass.

Parameters:
  • mass_kg – Body mass of the animal [kg].

  • terms – A tuple (intercept, exponent) for the log-log scaling relationship, where intercept and exponent act on ln(BM_g).

Returns:

Territory size [m²].

virtual_ecosystem.models.animal.scaling_functions.theta_opt_i(theta_opt_min_f: float, theta_opt_f: float, sigma_opt_f: float) float[source]#

Optimum predator-prey mass ratio.

TODO: update name

Madingley

Parameters:
  • theta_opt_min_f – The minimum optimal prey-predator body mass ratio.

  • theta_opt_f – The mean optimal prey-predator body mass ratio, from which actual cohort optima are drawn.

  • sigma_opt_f – The standard deviation of optimal predator-prey mass ratios among cohorts.

Returns:

A float measure of the optimum ratio.

virtual_ecosystem.models.animal.scaling_functions.w_bar_i_j(mass_predator: float, mass_prey: float, theta_opt_i: float, sigma_opt_pred_prey: float) float[source]#

The probability of successfully capturing a prey item.

TODO: update name

Madingley

Parameters:
  • mass_predator – Current mass of the predator..

  • mass_prey – Current mass of the prey.

  • theta_opt_i – The optimum predator-prey mass ratio.

  • sigma_opt_pred_prey – The standard deviation of the mass ratio.

Returns:

A float probability [0.0-1.0] that a predation encounter is successful.