Select Git revision
run_video.bat
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
marbled_white.jl 10.91 KiB
### Persefone.jl - a model of agricultural landscapes and ecosystems in Europe.
###
### This file holds the code for the Marbled White (Melanargia galathea).
###
##TODO
## - population initialisation
## - agglomeration?
"""
Marbled White
*Melanargia galathea* is a grassland specialist butterfly.
**Sources:**
- Baguette et al. (2000). Population spatial structure and migration
of three butterfly species within the same habitat network: Consequences
for conservation. Journal of Applied Ecology, 37(1), 100–108.
https://doi.org/10.1046/j.1365-2664.2000.00478.x
- Dennis (Ed.). (1992). The ecology of butterflies in Britain.
Oxford University Press.
- Ebert & Rennwald (1991). Die Schmetterlinge Baden-Württembergs,
Bd.2, Tagfalter: Satyridae, Libytheidae, Lycaenidae, Hesperiidae.
Verlag Eugen Ulmer.
- Evans et al. (2019). Integrating the influence of weather into mechanistic
models of butterfly movement. Movement Ecology, 7(1), 24.
https://doi.org/10.1186/s40462-019-0171-7
- Gotthard et al. (2007). What Keeps Insects Small? Time Limitation during
Oviposition Reduces the Fecundity Benefit of Female Size in a Butterfly.
The American Naturalist, 169(6), 768–779. https://doi.org/10.1086/516651
- Hannappel & Fischer (2020). Grassland intensification strongly reduces
butterfly diversity in the Westerwald mountain range, Germany. Journal
of Insect Conservation, 24(2), 279–285. https://doi.org/10.1007/s10841-019-00195-1
- Lenda & Skórka (2010). Patch occupancy, number of individuals and population
density of the Marbled White in a changing agricultural landscape. Acta
Oecologica, 36(5), 497–506. https://doi.org/10.1016/j.actao.2010.07.002
- Reinhardt et al. (2007): Tagfalter von Sachsen. In: Klausnitzer & Reinhardt
(Hrsg.) Beiträge zur Insektenfauna Sachsens Band 6. – Entomologische Nachrichten
und Berichte, Beiheft 11, 696 + 48 Seiten. Dresden.
- Roy et al. (2001). Butterfly numbers and weather: Predicting historical
trends in abundance and the future effects of climate change. Journal of
Animal Ecology, 70(2), 201–217. https://doi.org/10.1111/j.1365-2656.2001.00480.x
- Vandewoestijne et al. (2004). Dispersal, landscape occupancy and population
structure in the butterfly Melanargia galathea. Basic and Applied Ecology,
5(6), 581–591. https://doi.org/10.1016/j.baae.2004.07.004
"""
@species MarbledWhite begin
## SPECIES PARAMETERS
# habitat/environmental requirements
# (Height parameters from Vandewoestijne et al. 2004. For temperature parameters
# see Ebert & Rennwald 1991, Gotthard et al., 2007, and Evans et al. 2019)
const minheight = 30cm # minimum height of vegetation for egg-laying
const maxheight = 60cm # maximum height of vegetation for egg-laying
const mintemp = 18 # minimum temperature for activity (°C)
const maxtemp = 30 # maximum temperature for activity (°C)
# movement parameters
#FIXME these are arbitrary guesses!
const maxstepsperday = 100 # daily movement steps under optimal temperatures
const selfavoidance = 0.9
const habitatpreference = 0.9
const perception = 100m # perceptual range (cf. Cant et al. 2005)
# lifecycle parameters
# (eggsperday and time parameters from Reinhardt et al. 2007)
const maxeggsperday = 15 # number of eggs laid under optimal conditions
const eggtime = 18:22 # days as egg
const larvatime = 290:320 # days as larva
const pupatime = 16:29 # days as pupa
const adulttime = 17:34 # days as adult
const maturationtime = 5:8 # days from hatching to first oviposition
const juvenilesurvival = 0:25 # in percent (Wilson 1985, Dennis 1992)
const earliesteclosure::AnnualDate = (June, 15) # (Ebert & Rennwald 1991)
const latesteclosure::AnnualDate = (August, 15) # (Ebert & Rennwald 1991)
const enforceflyingperiod = true # make sure all pupa eclose in the flying period?
## INDIVIDUAL VARIABLES
birthdate::Date = Date(2000, July, 1) # is redefined in @create
# how many days this individual spends in each phase
daysinphase::Vector{Int64} = [20, 300, 19, 25] # is redefined in @create
# following::Int64 = -1 # ID of the individual being followed #XXX include this?
end
## LIFE PHASES
"""
Juvenile individuals (i.e. eggs, larvae, pupae) simply wait for the eclosing day.
"""
@phase MarbledWhite egg begin
if self.age >= self.daysinphase[1]
@setphase(larva)
end
end
"""
Juvenile individuals (i.e. eggs, larvae, pupae) simply wait for the eclosing day.
"""
@phase MarbledWhite larva begin
if self.age >= self.daysinphase[1]+self.daysinphase[2]
@setphase(pupa)
end
end
"""
Juvenile individuals (i.e. eggs, larvae, pupae) simply wait for the eclosing day.
"""
@phase MarbledWhite pupa begin
if self.age >= self.daysinphase[1]+self.daysinphase[2]+self.daysinphase[3]
@setphase(adult)
end
end
"""
**Adult marbled whites (we only simulate females) fly around more or less randomly
on days with good weather, laying eggs on suitable habitat.**
### Movement
Adults move a given number of steps each day, depending on the temperature (see below).
Each step, an individual scans its surroundings in concentric circles, looking for
the closest spot that offers suitable habitat which it hasn't visited today. (Depending
on the `habitatpreference` and `selfavoidance` parameters, spots that are not suitable
habitat or have been visited before may also be selected.) After each step, if it
is in a suitable habitat, the individual lays an egg, up to `maxeggsperday` (depending
on temperature, see below).
### Temperature
Temperature affects both the distance moved and the number of eggs laid each day.
The optimal temperature is taken to be the midway point between the species' minimum
and maximum temperatures (i.e. 24°C). Outside the species' temperature range (18-30°C),
neither movement nor oviposition take place. Within that range, the number of steps
each day peaks at the optimum temperature and declines linearly on either side of it.
(cf. Evans et al., 2019). The number of eggs laid declines linearly if the temperature
is below the optimum, but stays stable above it (cf. Gotthard et al., 2007).
The daily maximum temperature (rather than mean or minimum) is used as the measure of
choice, as this is most relevant for butterfly activity, and we don't have sub-daily
weather data.
"""
@phase MarbledWhite adult begin
# temperature dependence
opttemp = (self.mintemp + self.maxtemp)/2
optimality = bounds(1 - (abs(opttemp-@maxtemp()) / (opttemp-self.mintemp)))
stepsremaining::Int64 = Int(round(self.maxstepsperday*optimality))
eggsremaining::Int64 = self.maxeggsperday
if @maxtemp() < opttemp || @maxtemp() > self.maxtemp
eggsremaining = Int(round(self.maxeggsperday*optimality))
end
# movement
path::Vector{Tuple{Int64,Int64}} = [pos]
width, height = size(model.landscape)
while stepsremaining > 0
radius = 1
while radius <= self.perception
coords = []
xrange = (self.pos[1]-radius, self.pos[1]+radius)
yrange = (self.pos[2]-radius, self.pos[2]+radius)
for x in xrange[1]:xrange[2]
push!(coords, (x, yrange[1]))
push!(coords, (x, yrange[2]))
end
for y in (yrange[1]+1):(yrange[2]-1) #avoid duplicating the corners
push!(coords, (y, xrange[1]))
push!(coords, (y, xrange[2]))
end
for c in @shuffle!(coords)
(c[1] <= 0 || c[2] <= 0 || c[1] > width || c[2] > height) && continue
(c in path && @chance(self.selfavoidance)) && continue
(!suitablehabitat(self, mode, c) && @chance(habitatpreference)) && continue
radius = self.perception
@move(c)
break
end
radius += 1
end
# lay an egg if possible
if eggsremaining > 0 && suitablehabitat(self, model, pos)
if @chance(@randn(self.juvenilesurvival)/100)
@reproduce() # only create an individual that will survive to adulthood
end
eggsremaining -= 1
end
push!(path, self.pos)
stepsremaining -= 1
end
# die once the lifespan has been reached
if self.age >= sum(self.daysinphase)
@kill()
end
end
## SUPPORTING FUNCTIONS
"""
suitablehabitat(butterfly, model, pos)
Check whether the given position is suitable for oviposition. This means:
the land cover must be either grass or fallow, and if grass, must either not
be managed, or not have been fertilised and be a certain height.
"""
function suitablehabitat(butterfly::MarbledWhite, model::SimulationModel, pos::Tuple{Int64,Int64})
(@landcover() == agriculture && @cropname() == "set-aside") ||
(@landcover() == grass && (@cropname() == "NA" ||
(!(fertiliser in model.landscape[pos...].events) &&
@cropheight() >= butterfly.minheight &&
@cropheight() <= butterfly.maxheight)))
end
## INITIALISATION
"""
Initialise a marbled white individual. Mainly defines the time this individual
will spend in each phase. (This ought to be temperature-dependent rather than
random, but I don't have data for that.)
"""
@create MarbledWhite begin
@debug "Added $(animalid(self)) at $(self.pos)"
# set the birthdate (during initialisation, pick a random date last year)
if model.date >= self.earliesteclosure && model.date <= self.latesteclosure
self.birthdate = model.date
else
self.birthdate = @lastyear(@randn(self.earliesteclosure:self.latesteclosure))
self.age = (model.date - self.birthdate).value
end
# choose a normally-distributed random number of days to spend in each phase
self.daysinphase = [@randn(self.eggtime), @randn(self.larvatime),
@randn(self.pupatime), @randn(self.adulttime)]
# check whether eclosure is during the flight period, change the larval time if not
if self.enforceflyingperiod
eclose = self.birthdate + Day(sum(self.daysinphase))
if eclose < self.earliesteclosure
diff = @thisyear(self.earliesteclosure) - eclose
self.daysinphase[2] += diff.value
@debug("Increased larval time by $(diff) to stay in flying period.")
elseif eclose > self.latesteclosure
diff = eclose - self.latesteclosure
self.daysinphase[2] -= diff.value
@debug("Reduced larval time by $(diff) to stay in flying period.")
end
end
end
"""
Initialise the marbled white population with one individual on every grassland pixel.
"""
@populate MarbledWhite begin
habitat = @habitat(@landcover() == grass) #XXX too simple? (cf. suitablehabitat())
initphase = egg # this should advance within a few days to the correct phase
birthphase = egg
popsize = -1 # one individual per suitable location
sex = female
end