Nature

nature.jl

This file is responsible for managing the animal modules.

Persefone.AnimalType
Animal

This is the generic agent type for all animals. Species are differentiated by trait dictionaries passed by them during initialisation. (Note that each trait variable can still be accessed as if it were a normal field name, i.e. the trait phase can be accessed and modified with animal.phase.)

source
Persefone.animalidMethod
animalid(animal)

A small utility function to return a string with the species name and ID of an animal.

source
Persefone.stepagent!Method
stepagent!(animal, model)

Update an animal by one day, executing it's currently active phase function.

source
Persefone.@countanimalsMacro
@countanimals(species="", radius=0)

Count the number of animals of the given species in this location. This is a utility wrapper that can only be used nested within @phase or @habitat.

source
Persefone.@cropheightMacro
@cropheight

Return the height of the crop at this position, or 0 if there is no crop here. This is a utility wrapper that can only be used nested within @phase or @habitat.

source
Persefone.@cropnameMacro
@cropname

Return the name of the local croptype, or nothing if there is no crop here. This is a utility wrapper that can only be used nested within @phase or @habitat.

source
Persefone.@distancetoMacro
@distanceto(habitat)

Calculate the distance to the closest habitat of the specified type or descriptor. This is a utility wrapper that can only be used nested within @phase or @habitat.

source
Persefone.@habitatMacro
@habitat

Specify habitat suitability for spatial ecological processes.

This macro works by creating an anonymous function that takes in a model object and a position, and returns true or false depending on the conditions specified in the macro body.

Several utility macros can be used within the body of @habitat as a short-hand for common expressions: @landcover, @cropname, @cropheight, @distanceto, @distancetoedge, @countanimals. The variables model and pos can be used for checks that don't have a macro available.

Two example uses of @habitat might look like this:

movementhabitat = @habitat(@landcover() in (grass agriculture soil))

nestinghabitat = @habitat((@landcover() == grass || 
                           (@landcover() == agriculture && @cropname() != "maize" &&
                            @cropheight() < 10)) &&
                          @distanceto(forest) > 20)

For more complex habitat suitability checks, the use of this macro can be circumvented by directly creating an equivalent function.

source
Persefone.@initialiseMacro
@initialise(habitatdescriptor; kwargs...)

Call this macro within the body of @species. It passes the given habitat descriptor function and keyword arguments on to initpopulation when setting up the simulation.

Note: if this macro is not used, the variable initialise! must be set manually in the species definition.

source
Persefone.@killMacro
@kill

Kill this animal (and immediately abort its current update). This is a thin wrapper around kill!, and passes on any arguments. This can only be used nested within @phase.

source
Persefone.@neighboursMacro
@neighbours(radius)

Return an iterator over all animals in the given radius around this animal, excluding itself. This can only be used nested within @phase.

source
Persefone.@phaseMacro
@phase(name, body)

This macro is designed to be used within a species definition block (i.e. within the body of a call to @species).

The idea behind this is that species show very different behaviour during different phases of their lives. Therefore, @phase can be used define the behaviour for one such phase, and the conditions under which the animal transitions to another phase.

@phase works by creating a function that will be called by the model if the animal is in the relevant phase. When it is called, it has access to the following variables:

  • animal a reference to the animal itself. This provides access to animal.age, animal.sex, and animal.<trait> (where <trait> is a variable that was defined in the top part of the species definition body).
  • pos gives the animal's current position as a coordinate tuple.
  • model a reference to the model world (an object of type AgentBasedModel). This allows access to model.date (the current simulation date) and model.landscape (a two-dimensional array of pixels containing geographic information).

Several utility macros can be used within the body of @phase as a short-hand for common expressions: @trait, @setphase, @respond, @kill, @reproduce, @neighbours, @rand, @shuffle!.

Note that the first phase that is defined in a species definition block will be the phase that animals are assigned at birth, unless the variable phase is explicitly defined by the user in the species definition block.

source
Persefone.@respondMacro
@respond(eventname, body)

Define how an animal responds to a landscape event that affects its current position. This can only be used nested within @phase.

source
Persefone.@speciesMacro
@species(name, body)

A macro used to create new species definitions for the nature model. This is effectively a simple domain-specific language, establishing a custom syntax to describe species' biology:

@species name begin

    @initialise(@habitat(...))
    speciesvar1 = 3.14
    ...

    @phase phase1 begin
        ...
    end
end

The definition body (enclosed in the begin/end block) has two sections. First comes a call to @initialise, and optionally a list of species-specific parameters, which are assigned just like normal variables. Second come one or more phase definitions, that describe the behaviour of the species during various parts of its life cycle. (See the documentation to @initialise and @phase for details).

Code in a species definition block can access the rest of the model using the model variable (an object of type AgentBasedModel).

source
Persefone.@traitMacro
@trait(traitname)

A utility macro to quickly access an animal's trait value. This can only be used nested within @phase.

source

populations.jl

This file contains a set of utility functions for species, including initialisation, reproduction, and mortality.

Persefone.countanimalsMethod
countanimals(pos, model; species="", radius=0)

Count the number of animals in this location (optionally supplying a species name and radius).

source
Persefone.initpopulationMethod
initpopulation(habitatdescriptor; popsize=-1, pairs=false, asexual=false)

Creates a function that initialises individuals at random locations across the landscape. This can be used to create the initialise! variable in a species definition block.

  • habitatdescriptor is a function that determines whether a given location is suitable or not (create this using @habitat).

  • phase determines which life phase individuals will be assigned to. If this is nothing, the species' default post-natal life stage will be used (although note that this is probably not what you want).

  • popsize determines the number of individuals that will be created. If this is zero or negative, one individual will be created in every suitable location in the landscape. If popsize is greater than the number of suitable locations, multiple individuals will be created in one place. (Maximum population density can be set in the habitat descriptor using the @countanimals macro.)

  • If pairs is true, a male and a female individual will be created in each selected location, otherwise, only one individual will be created at a time.

  • If asexual is true, all created individuals are assigned the sex hermaphrodite, otherwise, they are randomly assigned male of female. (If pairs is true, asexual is ignored.)

source
Persefone.kill!Function
kill(animal, model, probability=1.0, cause="")

Kill this animal, optionally with a given percentage probability. Returns true if the animal dies, false if not.

source
Persefone.nearby_animalsMethod
nearby_animals(animal, model, radius)

Return an iterator over all animals in the given radius around this animal, excluding itself.

source
Persefone.nearby_animalsMethod
nearby_animals(pos, model, radius)

Return an iterator over all animals in the given radius around this position.

source
Persefone.reproduce!Function
reproduce!(animal, model, n=1)

Produce one or more offspring for the given animal at its current location.

source

insects.jl

This file contains the insect submodel, which calculates the likely insect biomass in a given location at a given time.

Persefone.insectbiomassMethod
insectbiomass(pixel, model)

Calculate the insect biomass in this location, using the factors configured in the nature.insectmodel settings (any combination of: "season", "habitat", "weather", "pesticides"). Returns a float value in g/m².

Biological note: this is a very approximate calculation! Insect biomass varies wildly in time and space and is hard to measure. This calculation is based on the idea of a parabolic seasonal development of insect abundance, modified by habitat suitability, weather, and pesticide application. Although it is based on empirical studies, it can only deliver a rough, order-of-magnitude estimation of likely insect biomass in a given location.

Sources:

  • Odderskær et al. (1997). Skylark Reproduction in Pesticide Treated and Untreated Fields (32; Pesticides Research). Danish Environmental Protection Agency.
  • Grüebler et al. (2008). A predictive model of the density of airborne insects in agricultural environments. Agriculture, Ecosystems & Environment, 123(1), 75–80. https://doi.org/10.1016/j.agee.2007.05.001
  • Paquette et al. (2013). Seasonal patterns in Tree Swallow prey (Diptera) abundance are affected by agricultural intensification. Ecological Applications, 23(1), 122–133. https://doi.org/10.1890/12-0068.1
  • Püttmanns et al. (2022). Habitat use and foraging parameters of breeding Skylarks indicate no seasonal decrease in food availability in heterogeneous farmland. Ecology and Evolution, 12(1), e8461. https://doi.org/10.1002/ece3.8461
source

ecologicaldata.jl

This file contains a set of life-history related utility functions needed by species.

Persefone.saveindividualdataMethod
saveindividualdata(model)

Return a comma-separated set of lines (to be printed to individuals.csv), listing all properties of all animal individuals in the model. May be called never, daily, monthly, yearly, or at the end of a simulation, depending on the parameter nature.indoutfreq. WARNING: Produces very big files!

source
Persefone.savepopulationdataMethod
savepopulationdata(model)

Return a comma-separated set of lines (to be printed to populations.csv), giving the current date and population size for each animal species. May be called never, daily, monthly, yearly, or at the end of a simulation, depending on the parameter nature.popoutfreq.

source