Public documentation

Documentation for EcologicalNetworksDynamics.jl public interface.

Index

Public Interface

Functions

EcologicalNetworksDynamics.default_modelMethod
default_model(
foodweb::Foodweb;
kwargs...

)

Generate a model from a food web with parameters set to default values.

Let's first illustrate the use of default_model with a simple example.

foodweb = Foodweb([1 => 2])
default_model(foodweb)

In this example, all parameters are set to default values, however for your needs, you can override any of the default parameters. For instance, if you want to override the default metabolic rate, you can do it as follows:

my_x = [0.0, 1.2] # One value per species.
default_model(foodweb, Metabolism(my_x))
source
EcologicalNetworksDynamics.persistenceMethod
persistence(solution::AbstractODESolution; threshold = 0)

Fraction of alive species at each timestep of the simulation. See richness for details.

Examples

julia> S = 20 # Initial number of species.
       foodweb = Foodweb(:niche; S = 20, C = 0.1)
       m = default_model(foodweb)
       B0 = rand(S)
       sol = simulate(m, B0)
       all(persistence(sol) .== richness(sol) / S)
true
source
EcologicalNetworksDynamics.richnessMethod
richness(vec::AbstractVector; threshold = 0)

Return the number of alive species given a biomass vector vec. By default, species are considered extinct if their biomass is 0. But, this threshold can be changed using the corresponding keyword argument.

Examples

julia> foodweb = Foodweb([0 0; 1 0])
       m = default_model(foodweb)
       B0 = [0.5, 0.5]
       sol = simulate(m, B0)
       richness(sol[end]) # Richness at the end of the simulation.
2.0
source
EcologicalNetworksDynamics.richnessMethod

richness(solution::Solution; threshold = 0)

Return the number of alive species at each timestep of the simulation. solution is the output of simulate. By default, species are considered extinct if their biomass is 0. But, this threshold can be changed using the corresponding keyword argument.

Examples

Let's start with a simple example where the richness remains constant:

julia> foodweb = Foodweb([0 0; 1 0])
       m = default_model(foodweb)
       B0 = [0.5, 0.5]
       sol = simulate(m, B0)
       richness_trajectory = richness(sol)
       all(richness_trajectory .== 2) # At each timestep, there are 2 alive species.
true

Now let's assume that the producer is extinct at the beginning of the simulation, while its consumer is not. We expect to observe a decrease in richness from 1 to 0 over time.

julia> B0 = [0, 0.5] # The producer is extinct at the beginning.
       sol = simulate(m, B0)
       richness_trajectory = richness(sol)
       richness_trajectory[1] == 1 && richness_trajectory[end] == 0
true
source
EcologicalNetworksDynamics.shannon_diversityMethod
shannon_diversity(vec::AbstractVector; threshold = 0)

Shannon diversitty index given a biomass vector `vec Shannon diversity is a measure of species diversity based on the entropy. According to the Shannon index, for a same number of species, the more evenly the biomass is distributed among them, the higher the diversity.

Example

We consider a simple example with 3 species, but different shannon diversity.

julia> s1 = shannon_diversity([1, 1, 1])
       s2 = shannon_diversity([1, 1, 0.1])
       s3 = shannon_diversity([1, 1, 0.01])
       s1 > s2 > s3
true

We observe as we decrease the biomass of the third species, the shannon diversity tends to 2, as we tend towards an effective two-species community.

source
EcologicalNetworksDynamics.shannon_diversityMethod
shannon_diversity(solution::AbstractODESolution; threshold = 0)

Shannon diversity index at each timestep of the simulation. solution is the output of simulate. Shannon diversity is a measure of species diversity based on the entropy. According to the Shannon index, for a same number of species, the more evenly the biomass is distributed among them, the higher the diversity.

Example

We start a simple simulation with even biomass distribution, therefore we expect the Shannon diversity to decrease over time as the biomass of the species diverge from each other.

julia> foodweb = Foodweb([0 0; 1 0])
       m = default_model(foodweb)
       B0 = [0.5, 0.5] # Even biomass, maximal shannon diversity.
       sol = simulate(m, B0)
       shannon_trajectory = shannon_diversity(sol)
       biomass_trajectory[1] > biomass_trajectory[end]
true
source
EcologicalNetworksDynamics.total_biomassMethod
total_biomass(solution::AbstractODESolution)

Total biomass of a community at each timestep of the simulation. solution is the output of simulate.

Example

Let's consider a consumer feeding on a producer, and let's start the simulation with the producer extinction so we can observe the consumer's biomass decrease over time.

julia> foodweb = Foodweb([0 0; 1 0])
       m = default_model(foodweb)
       B0 = [0, 0.5] # The producer is extinct at the beginning.
       sol = simulate(m, B0)
       biomass_trajectory = total_biomass(sol)
       biomass_trajectory[1] == 0.5 && biomass_trajectory[end] == 0
true
source

Types

EcologicalNetworksDynamics.FoodwebType

The Foodweb component, aka. "Trophic layer", adds a set of trophic links connecting species in the model. This is one of the most structuring components.

Blueprint Creation from Raw Links.

From an adjacency list:

julia> fw = Foodweb([:a => :b, :b => [:c, :d]])
blueprint for Foodweb with 2 trophic links:
  A:
  :a eats :b
  :b eats :c and :d

julia> Model(fw) # Automatically brings a 'Species' component.
Model with 2 components:
  - Species: 4 (:a, :b, :c, :d)
  - Foodweb: 3 links

julia> Model(Foodweb([4 => [2, 1], 2 => 1])) #  From species indices.
Model with 2 components:
  - Species: 4 (:s1, :s2, :s3, :s4)
  - Foodweb: 3 links

From a matrix:

julia> fw = Foodweb([0 0 1; 1 0 1; 0 0 0])
blueprint for Foodweb with 3 trophic links:
  A: 3×3 SparseArrays.SparseMatrixCSC{Bool, Int64} with 3 stored entries:
 ⋅  ⋅  1
 1  ⋅  1
 ⋅  ⋅

julia> Model(fw)
Model with 2 components:
  - Species: 3 (:s1, :s2, :s3)
  - Foodweb: 3 links

Blueprint Creation from Random Models.

Cascade model: specify the desired number of species S and connectance C.

julia> using Random
       Random.seed!(12)
       fw = Foodweb(:cascade; S = 5, C = 0.2)
blueprint for Foodweb with 5 trophic links:
  A: 5×5 SparseArrays.SparseMatrixCSC{Bool, Int64} with 5 stored entries:
 ⋅  1  ⋅  1  1
 ⋅  ⋅  ⋅  ⋅  ⋅
 ⋅  ⋅  ⋅  1  ⋅
 ⋅  ⋅  ⋅  ⋅  1
 ⋅  ⋅  ⋅  ⋅  ⋅

Random foodwebs are drawn until the desired connectance is obtained, within a tolerance level defaulted to tol_C = 0.1 * C, modifiable as a keyword argument.

Niche model: either specify the connectance C or number of links L.

julia> fw = Foodweb(:niche; S = 5, C = 0.2) #  From connectance.
blueprint for Foodweb with 5 trophic links:
  A: 5×5 SparseArrays.SparseMatrixCSC{Bool, Int64} with 5 stored entries:
 ⋅  ⋅  ⋅  ⋅  ⋅
 ⋅  ⋅  ⋅  ⋅  ⋅
 1  1  ⋅  ⋅  ⋅
 ⋅  ⋅  1  ⋅  ⋅
 1  1  ⋅  ⋅  ⋅

julia> fw = Foodweb(:niche; S = 5, L = 4) #  From number of links.
blueprint for Foodweb with 4 trophic links:
  A: 5×5 SparseArrays.SparseMatrixCSC{Bool, Int64} with 4 stored entries:
 ⋅  ⋅  ⋅  ⋅  ⋅
 ⋅  ⋅  ⋅  ⋅  ⋅
 ⋅  ⋅  ⋅  ⋅  ⋅
 1  ⋅  ⋅  ⋅  ⋅
 1  1  1  ⋅  ⋅

The default tolerance levels for the niche model are tol_C = 0.1 * C and tol_L = 0.1 * L, modifiable as keyword arguments.

For either random model, the following keyword arguments can also be specified:

  • reject_cycles = false (default): raise to forbid trophic cycles.
  • reject_if_disconnected = true (default): lower to allow disconnected trophic networks.
  • max_iterations = 10^5 (default): give up if no satisfying network can be found after this number of random trials.

Properties.

A model m with a Foodweb has the following properties.

  • m.A or m.trophic_links: a view into the matrix of trophic links.
  • m.n_trophic_links: the number of trophic links in the model.
  • m.trophic_levels: calculate the trophic level of every species in the model.
  • Distinguishing between producers (species without outgoing trophic links) and consumers (species with outgoing trophic links):
    • m.{producers,consumers}_mask: a boolean vector to select either kind of species.
    • m.n_{producers,consumers}: count number of species of either kind.
    • is_{producer,consumer}(m, i): check whether species i (name or index) is of either kind.
    • m.{producers,consumer}_indices: iterate over either species kind indices.
    • m.{producers,consumer}_{sparse,dense}_index: obtain a $species\_name \mapsto species\_index$ mapping:
      • the sparse index yields indices valid within the whole collection of species.
      • the dense index yields indices only valid within the restricted collection of species of either kind.
  • Distinguishing betwen preys (species with incoming trophic links) and tops predators (species without incoming trophic links) works the same way.
  • m.producers_links: boolean matrix highlighting potential links between producers.
  • m.herbivorous_links: highlight only consumer-to-producer trophic links.
  • m.carnivorous_links: highlight only consumer-to-consumer trophic links.
julia> m = Model(Foodweb([:a => :b, :b => [:c, :d], :d => :e]));

julia> m.n_trophic_links
4

julia> m.A
5×5 EcologicalNetworksDynamics.TrophicLinks:
 0  1  0  0  0
 0  0  1  1  0
 0  0  0  0  0
 0  0  0  0  1
 0  0  0  0  0

julia> m.trophic_levels
5-element EcologicalNetworksDynamics.TrophicLevels:
 3.5
 2.5
 1.0
 2.0
 1.0

julia> m.producers_mask
5-element EcologicalNetworksDynamics.ProducersMask:
 0
 0
 1
 0
 1

julia> m.preys_mask
5-element EcologicalNetworksDynamics.PreysMask:
 0
 1
 1
 1
 1

julia> m.n_producers, m.n_consumers
(2, 3)

julia> m.n_tops, m.n_preys
(1, 4)

julia> is_top(m, 1), is_top(m, 2)
(true, false)

julia> collect(m.consumers_indices)
3-element Vector{Int64}:
 1
 2
 4

julia> m.producers_sparse_index
OrderedCollections.OrderedDict{Symbol, Int64} with 2 entries:
  :c => 3
  :e => 5

julia> m.producers_dense_index
OrderedCollections.OrderedDict{Symbol, Int64} with 2 entries:
  :c => 1
  :e => 2

julia> m.producers_links
5×5 EcologicalNetworksDynamics.ProducersLinks:
 0  0  0  0  0
 0  0  0  0  0
 0  0  1  0  1
 0  0  0  0  0
 0  0  1  0  1

julia> m.herbivorous_links
5×5 EcologicalNetworksDynamics.HerbivorousLinks:
 0  0  0  0  0
 0  0  1  0  0
 0  0  0  0  0
 0  0  0  0  1
 0  0  0  0  0

julia> m.carnivorous_links
5×5 EcologicalNetworksDynamics.CarnivorousLinks:
 0  1  0  0  0
 0  0  0  1  0
 0  0  0  0  0
 0  0  0  0  0
 0  0  0  0  0
source
EcologicalNetworksDynamics.ModelType

Model is the main object that we hand out to user which contains all the information about the underlying ecological model.

Create a Model

The most straightforward way to create a model is to use default_model. This function only requires you to specify the trophic network.

fw = [1 => 2, 2 => 3]
model = default_model(fw)

This function will help you to create a model with ease, however it relies on default values for the parameters, which are not always suitable for your specific case, even though extracted from the literature.

To create a model with custom parameters, you can pass other arguments to default_model.

model = default_model(fw, BodyMass(; Z = 100))

For instance, the above example creates a model with a body mass distribution with a predator-prey mass ratio of 100.

It is also possible to create a model manually by adding the components one by one. First, create an empty model:

m = Model()

Then add your components one by one. Note that you have to add the components in the right order, as some components depend on others. Moreover, some components are mandatory. Specifically, you need to provide a food web, species body masses, a functional response, metabolic rates and a producer growth function.

m = Model()
m += Foodweb([3 => 2, 2 => 1])
m += ClassicResponse(; h = 2, M = BodyMass([0.1, 2, 3]))
m += LogisticGrowth(; r = 1, K = 10)
m += Metabolism(:Miele2019)
m += Mortality(0)

Read and write properties of the model

First all properties contained in the model can be listed with:

properties(m) # Where m is a Model.

Then, the value of a property can be read with get_<X> where X is the name of the property. For instance, to read mortality rates:

get_mortality(m) # Equivalent to: m.mortality.

You can also re-write properties of the model using set_<X>!. However, not all properties can be re-written, because some of them are derived from the others. For instance, many parameters are derived from species body masses, therefore changing body masses would make the model inconsistent. However, terminal properties can be re-written, as the species metabolic rate.

source
EcologicalNetworksDynamics.SpeciesType

The Species component adds the most basic nodes compartment into the model: species. There is one node per species, and every species is given a unique name and index. The species ordering specified in this compartment is the reference species ordering.

julia> sp = Species(["hen", "fox", "snake"])
blueprint for Species:
  names: 3-element Vector{Symbol}:
 :hen
 :fox
 :snake

julia> m = Model(sp)
Model with 1 component:
  - Species: 3 (:hen, :fox, :snake)

julia> Model(Species(5)) # Default names generated.
Model with 1 component:
  - Species: 5 (:s1, :s2, :s3, :s4, :s5)

Typically, the species component is implicitly brought by other blueprints.

julia> Model(Foodweb([:a => :b]))
Model with 2 components:
  - Species: 2 (:a, :b)
  - Foodweb: 1 link

julia> Model(BodyMass([4, 5, 6]))
Model with 2 components:
  - Species: 3 (:s1, :s2, :s3)
  - Body masses: [4.0, 5.0, 6.0]

The species component makes the following properties available to a model m:

  • m.S or m.richness or m.species_richness or m.n_species: number of species in the model.
  • m.species_names: list of species name in reference order.
  • m.species_index: get a $species\_name \mapsto species\_index$ mapping.
julia> (m.S, m.richness, m.species_richness, m.n_species) # All aliases for the same thing.
(3, 3, 3, 3)

julia> m.species_names
3-element EcologicalNetworksDynamics.SpeciesNames:
 :hen
 :fox
 :snake

julia> m.species_index
OrderedCollections.OrderedDict{Symbol, Int64} with 3 entries:
  :hen   => 1
  :fox   => 2
  :snake => 3
source