Community and ecosystem ecologists have long sought to understand the diversity, properties, and dynamics of multi-species assemblages. The characteristics of communities emerge in unpredictable ways because species influence one another through direct, and indirect, ecological interactions. Seeing that the coexistence of populations is constrained at least by feeding interactions, models of the relationship between resources and consumers have provided a useful and frequent tool in studying the theory of community dynamics. Although these modeling efforts started from simple, abstract models like those from the Lotka-Volterra family [@baca11lvp], more tailored and parameterized models have emerged whose goal was to include a broader range of ecological and biological mechanisms, thus hopefully providing more realistic representations of empirical systems. Among these, the "bio-energetic" model of @yodz92bsc is a general representation of resource-consumer dynamics, yielding results comparable to empirical systems, while needing minimal parameters. To achieve this purpose, it uses allometric scaling of metabolic biomass production and feeding rates, meaning that the flow of biomass from a resource to its consumer depends on their body mass.
Since the work of @yodz92bsc, @ches08ipc have shown that the dynamics of
ecological communities are driven not only by pairwise interactions, but also by
the fact that these interactions are embedded in larger networks, and @berl04isf
show how disturbances affecting species biomass or density cascade up, not only
to the species that they interact with, but with species up to two degrees of
separation from the original perturbation. In this context, models of energy
transfer through trophic interactions are better justified when they account for
the entire food-web structure, such as @will07hyi adaptation to food webs of
@yodz92bsc model. This food-web bio-energetic model has been used, for example,
to show how food web stability can emerge from allometric scaling [@bros06ase]
or allometry-constrained degree distributions [@otto07add] (more past uses of the model are described in supplementary table S1). Yet, although these
and other studies used the same mathematical model, implementations differ from
study to study and none have been released. Motivated by the fact that this
model addresses mechanisms that are fundamental to our understanding of energy
flow throughout food webs, we present befwm
(Bio-Energetic Food-Webs Model), a
Julia package implementing @yodz92bsc bio-energetic model adapted for
food webs [@will07hyi] with updated allometric coefficients [@bros06ase;
@brow04mte].
This package aims to offer an efficient common ground for modeling food-web dynamics, to make investigations of this model easier, and to facilitate reproducibility and transparency of modeling efforts. Taking a broader perspective, we argue that providing the community with reference implementations of common models is an important task. First, implementing complex models can be a difficult task, in which programming mistakes will bias the output of the simulations, and therefore the ecological interpretations we draw from them. Second, reference implementations facilitate the comparison of studies. Currently, comparing studies mean not only comparing results, but also comparing implementations -- because not all code is public, a difference in results cannot be properly explained as an error in either studies, and this eventually generates more uncertainty than it does answers. Finally, reference implementation eases reproducibility a lot. Specifically, it becomes enough to specify which version of the package was used, and to publish the script used to run the simulations (as we, for example, do in this manuscript). We fervently believe that more effort invested in providing the community with reference implementation of models representing cornerstones of our ecological understanding is important.
We implement the model as described by @bros06ase, which is itself explained in greater detail in @will07hyi. This model describes the flows of biomass across trophic levels, primarily defined by body size. It distinguishes populations based on two variables known to drive many biological rates: body mass (how large an organism is, i.e. how much biomass it stocks) and metabolic type (where the organism get its biomass from, and how it is metabolized). Once this distinction made, it models populations as simple stocks of biomass growing and shrinking through consumer-resources interactions. The governing equations below describe the changes in relative density of producers and consumers respectively.
\begin{equation}\label{e:producer} B'i = r_i G_i B_i -\sum{j \in \text{consumers}}\frac{x_jy_jB_jF_{ji}}{e_{ji}} \end{equation}
\begin{equation}\label{e:consumer} B'i = -x_iB_i+\sum{j \in \text{resources}} x_iy_iB_iF_{ij}-\sum_{j \in \text{consumers}}\frac{x_jy_jB_jF_{ji}}{e_{ji}} \end{equation}
where
\begin{equation}\label{e:func_resp} F_{ij}=\frac {\omega_{ij}B_{j}^{h}}{B_{0}^{h}+c_iB_iB_{0}^{h}+\sum_{k=resources}\omega_{ik}B_{k}^{h}} \end{equation}
The formulation of the growth rate
In equation \autoref{e:func_resp},
As almost all organism metabolic characteristics vary predictably with body mass [@brow04mte], these variations can be described by allometric relationships as described in @bros06ase. Hence, the per unit biomass biological rates of production, metabolism and maximum consumption follow negative power-law relationships with the typical adult body mass [@pric12tmt; @sava04ebs].
\begin{equation}\label{e:production_rate} R_P = a_r M_P^{-0.25} \end{equation}
\begin{equation}\label{e:metab_rate} X_C = a_x M_C^{-0.25} \end{equation}
\begin{equation}\label{e:maxcons_rate} Y_C = a_y M_P^{-0.25} \end{equation}
Where the subscripts P and C refer to producers and consumers populations
respectively, M is the typical adult body mass, and
\begin{equation}\label{e:norm_production_rate} r_i = \frac {a_r M_P^{-0.25}} {a_r M_P^{-0.25}} = 1 \end{equation}
\begin{equation}\label{e:norm_metab_rate} x_i = \frac {a_x M_C^{-0.25}} {a_r M_P^{-0.25}} = \frac {a_x} {a_r} (\frac {M_C} {M_P})^{0.25} \end{equation}
In equations \autoref{e:producer} and \autoref{e:consumer},
\begin{equation}\label{e:norm_maxcons_rate} y_i = \frac {Y_C} {X_C} = \frac {\frac {a_y M_P^{-0.25}} {a_r M_P^{-0.25}}} { \frac{a_x M_C^{-0.25}} {a_r M_P^{-0.25}}} = \frac {a_y} {a_x} \end{equation}
As the biological rates also vary with the organisms metabolic types, the maximum
consumption rate of population
Assuming that most natural food webs have a constant size structure [@bros06cbr;
@hatt15ppl], the consumer-resource body-mass ratio (
\begin{equation}\label{e:z_ratio} M_C = Z^{T-1} \end{equation}
Where
All of these parameters can be modified before running the simulations (see
?model_parameters
), and are saved alongside the simulation output for future
analyses. The default values and meanings of the different parameters are
explained in the documentation of the model_parameters
function. The user can
specify which species are ectotherm vertebrates by supplying an array of boolean
values, and the body-mass of each species by supplying an array of
floating-point values.
The core function simulate
performs the main simulation loop. It takes two
arguments, p
-- the dictionary generated through the model_parameters
function and containing the entire set of parameters -- and biomass
, a vector
that contains the initial biomasses for every population. Three keywords
arguments can be used to define the initial (start
) and final (stop
) times
as well as the integration method (use
, see ?simulate
or the on-line
documentation for more details on the numerical integration methods available).
This function returns an object with a fixed format, made of three fields: :p
has all the parameters used to start the simulation (including the food web
itself), :t
has a list of all timesteps (including intermediate integration
points), and :B
is is a matrix of biomasses for each population (columns) over
time (rows). All measures on output described below operate on this object.
The output of simulations can be saved to disk in either the JSON
(javascript
object notation) format, or in the native jld
format. The jld
option should
be preferred since it preserves the structure of all objects (JSON
should be
used when the results will be analyzed outside of Julia
, for example in R
).
The function to save results is called befwm.save
(note that befwm.
in front
is mandatory, to avoid clashes with other functions called save
in base
Julia
or other packages).
The befwm
package implements a variety of measures that can be applied on the
objects returned by simulations. All measures take an optional keyword argument
last
, indicating over how many timesteps before the end of the simulations the
results should be averaged.
Total biomass (total_biomass
) is the sum of the biomasses across all
populations. It is measured based on the populations biomasses
(population_biomass
).
The number of remaining species (species_richness
) is measured as the number
of species whose biomass is larger than an arbitrary threshold. Since befwm
uses robust adaptive numerical integrators (such as ODE45 and ODE78) the
threshold default value is species_richness
is
species_persistence
, which is the number of persisting species divided by the
starting number of species. A value of species_persistence
of 1 means that all
species persisted. A value of species_persistence
of 0 indicates that all
species went extinct.
Shannon's entropy (foodweb_diversity
) is used to measure diversity within the
food web. This measure is corrected for the total number of populations. This
returns values in
\begin{equation} H = - \frac{\sum b \times \text{log}(b)}{\text{log}(n)},, \end{equation}
where
Finally, we used the negative size-corrected coefficient of variation to assess
the temporal stability of biomass stocks across populations
(population_stability
). This function accepts an additional threshold
argument, specifying the biomass below which populations are excluded from the
analysis. For the same reason as for the species_richness
threshold, we
suggest that this value be set to either the machine's
The befwm
package is available for the julia
programming language, and is
continuously tested on the current version of Julia
, as well as the release
immediately before, as well as on the current development version. Julia
is an
ideal platform for this type of models, since it is easy to write, designed for
numerical computations, extremely fast, easily parallelized, and has good
numerical integration libraries. The package can be installed from the Julia
REPL using Pkg.add("befwm")
. A user manual and function reference is available
online at
http://poisotlab.io/BioEnergeticFoodWebs.jl/latest/, which also
gives instructions about installing Julia, the package, and how to get started.
The code is released under the MIT license. This software note describes version
0.1.0
. The source code of the package can be viewed, downloaded, and worked on
at https://github.com/PoisotLab/BioEnergeticFoodWebs.jl. Potential issues with
the code or package can be reported through the Issues system. The code is
version-controlled, undergoes continuous integration, and has a code coverage of
approx. 90% to this date.
All functions in the package have an in-line documentation available at http://poisotlab.io/BioEnergeticFoodWebs.jl/latest/, as well as from the
julia
interface by typing ?
followed by the name of the function. In this
section, we will describe three of the aforementionned use-cases. The code to
execute them is attached as Supp. Mat. to this paper. As all code in the
supplementary material uses Julia
's parallel computing abilities, it will
differ slightly from the examples given in the paper. For all figures, each
point is the average of at least 500 replicates. We conducted the simulations in
parallel on 50 Intel Xeon cores at 2.00 Ghz. All random networks were generated
using the implementation of the niche model of food webs [@will00sry] provided
in befwm
.
Starting from networks generated with the niche model, with 20 species,
connectance of
!{carrying}
We run the simulations with the default parameters (given in
?model_parameters
, and in the manual). Each simulation consists of the
following code:
# We generate a random food web
A = nichemodel(20, 0.15)
# This loop will keep on trying food webs
# until one with a connectance close enough
# to 0.15 is found
while abs(befwm.connectance(A)-0.15)>0.01
A = nichemodel(20, 0.15)
end
# Prepare the simulation parameters
for α in linspace(0.92, 1.08, 3)
for K in logspace(-1, 1, 9)
p = model_parameters(A, α=α,
K=K,
productivity=:competitive)
# We start each simulation with
# random biomasses in ]0;1[
bm = rand(size(A, 1))
# And finally, we simulate.
out = simulate(p, bm, start=0,
stop=2000, use=:ode45)
# And measure the output
diversity = foodweb_diversity(out,
last=1000,
threshold=eps())
end
end
The results are presented in \autoref{carrying}.
In \autoref{vertebrate}, we illustrate how the effect of body-mass ratio differs between food webs with invertebrates and ectotherm vertebrate consumers.
!{vertebrate}
The body-mass ratio is controlled by the parameter Z
in the
code), and can be changed in the following way:
scaling = logspace(-2, 4, 19) #creates an array with 19 body-mass ratio values
# Prepare the simulation parameters
p = model_parameters(A, Z=scaling[i]) #where i is a number from 1 to 19
Which species is an ectotherm vertebrate is controlled by the parameter
vertebrate
of model_parameters
, which is an array of boolean (true/false)
values. In order to have all consumers be ectotherm vertebrates, we use
vert = round(Bool,trophic_rank(A).>1.0)
so that for each network, we prepare the simulations with
# Prepare the simulation parameters
p = model_parameters(A,
Z=scaling[i],
vertebrates=vert)
# where i is a number from 1 to 19, as there are 19 body-mass ratio values in the
# scaling array
We investigate the effect of connectance on species coexistence under different
scenarios of inter-specific competition rates between producers
(\autoref{connectance}). These simulations therefore measure how the persistence
of the entire food web is affected by competition at the most basal trophic
level. The persistence, which we use as the measure of coexistence, is the
number of remaining species (i.e. with a biomass larger than eps()
), divided
by the initial number of species (20) -- note that there is also a
species_persistence
function built-in.
!{connectance}
for co in vec([0.05 0.15 0.25])
# We generate a random food web
A = nichemodel(20, co)
while abs(befwm.connectance(A)-co)>0.01
A = nichemodel(20, co)
end
# Prepare the simulation parameters
for α in linspace(0.8, 1.2 , 7)
p = model_parameters(A, α=α,
productivity=:competitive)
bm = rand(size(A, 1))
# And finally, we simulate.
out = simulate(p, bm, start=0,
stop=2000, use=:ode45)
# And measure the output
persistence = species_richness(out,
last=1000,
threshold=eps()) / 20
end
end
Values of
We presented befwm
, a reference implementation of the bio-energetic model
applied to food webs. We provided examples that can serve as templates to
perform novel simulation studies or use this model as an effective teaching
tool. Because the output can be exported in a language-neutral format (JSON),
the results obtained with this model can be analayzed in other languages that
are currently popular with ecologists, such as R
, python
, or MatLab
.
Because we provide a general implementation that covers some of the modications
made to this model over the years, there is a decreased need for individual
scientists to start their own implementation, which is a both a time consuming
and potentially risky endeavor.
Acknowledgements TP acknowledges financial support from NSERC, and an
equipment grant from FRQNT. We thank the developers and maintainers of
ODE.jl
.