Skip to content
Snippets Groups Projects
Commit d529d60a authored by xo30xoqa's avatar xo30xoqa
Browse files

Added stats recording for the marbled white

parent 2b25a290
Branches
Tags
No related merge requests found
......@@ -137,11 +137,10 @@ function initmarbledwhitedata(model::SimulationModel)
newdataoutput!(model, "marbledwhite_abundance",
["Date", "TotalAbundance", "Eggs", "Larvae", "Pupae", "Adults"],
@param(nature.popoutfreq), marbledwhiteabundance, marbledwhitepopulation)
# newdataoutput!(model, "marbledwhite_territories", ["Date", "ID", "X", "Y"],
# marbledwhiteterritories, "monthly") #TODO add plotting function
# newdataoutput!(model, "marbledwhite_breeding",
# ["Date", "Female", "Male", "X", "Y", "Landcover", "Crop", "Territory"],
# @param(nature.popoutfreq), nothing, marbledwhitestats) #TODO add
newdataoutput!(model, "marbledwhite_lifestats",
["ID", "Fecundity", "Daily movement", "Displacement", "Unmanaged grassland",
"Extensive grassland", "Fallow", "Intensive grassland", "Arable", "Other"],
@param(nature.popoutfreq), nothing, marbledwhitelifestats) #TODO add
end
"""
......
......@@ -3,10 +3,6 @@
### This file holds the code for the Marbled White (Melanargia galathea).
###
##TODO
## - population initialisation
## - agglomeration?
"""
Marbled White
......@@ -41,6 +37,8 @@
- 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
- Schulte et al. (2007). Die Tagfalter der Pfalz—Band 2. Gesellschaft für
Naturschutz und Ornithologie Rheinland-Pfalz.
- 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
......@@ -62,26 +60,32 @@
const selfavoidance = 0.9
const habitatpreference = 0.9
const perception = 100m # perceptual range (cf. Cant et al. 2005)
const socialdistancing = true # avoid pixels already occupied by conspecifics
# lifecycle parameters
# (eggsperday and time parameters from Reinhardt et al. 2007)
const maxeggsperday = 15 # number of eggs laid under optimal conditions
const maxeggsperday = 8 # number of eggs laid under optimal conditions #TODO recalculate
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 maturationtime = 5:8 # days from hatching to first oviposition #FIXME include
const juvenilesurvival = 0:5 #0:25 # in percent (Wilson 1985, Dennis 1992)
#TODO add mowing mortality
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
# life-history related
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?
# needed for statistics
birthplace::Tuple{Int64,Int64} = (0,0) # is redefined in @create
lifestats::Dict{String,Int64} = Dict("Fecundity"=>0, "Unmanaged grassland"=>0, "Extensive grassland"=>0,
"Fallow"=>0, "Intensive grassland"=>0, "Arable"=>0, "Other"=>0)
end
......@@ -124,7 +128,8 @@ Adults move a given number of steps each day, depending on the temperature (see
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
habitat or have been visited before may also be selected.) If `socialdistancing` is true,
spots that are already occupied by a conspecific are avoided. After each step, if it
is in a suitable habitat, the individual lays an egg, up to `maxeggsperday` (depending
on temperature, see below).
......@@ -146,6 +151,7 @@ weather data.
opttemp = (self.mintemp + self.maxtemp)/2
optimality = bounds(1 - (abs(opttemp-@maxtemp()) / (opttemp-self.mintemp)))
stepsremaining::Int64 = Int(round(self.maxstepsperday*optimality))
#FIXME consider maturationtime
eggsremaining::Int64 = self.maxeggsperday
if @maxtemp() < opttemp || @maxtemp() > self.maxtemp
eggsremaining = Int(round(self.maxeggsperday*optimality))
......@@ -168,11 +174,15 @@ weather data.
push!(coords, (y, xrange[2]))
end
for c in @shuffle!(coords)
# ignore undesirable habitats
(c[1] <= 0 || c[2] <= 0 || c[1] > width || c[2] > height) && continue
(self.socialdistancing && countanimals(c, model, species="MarbledWhite") > 0) && continue
(c in path && @chance(self.selfavoidance)) && continue
(!suitablehabitat(self, model, c) && @chance(self.habitatpreference)) && continue
radius = self.perception / @param(world.mapresolution)
# move to the new location and record habitat stats
radius = self.perception / @param(world.mapresolution) # end the outer loop
@move(c)
recordmovementstats(self, model)
break
end
radius += 1
......@@ -182,13 +192,16 @@ weather data.
if @chance(@randn(self.juvenilesurvival)/100)
@reproduce() # only create an individual that will survive to adulthood
end
self.lifestats["Fecundity"] += 1
eggsremaining -= 1
end
push!(path, self.pos)
stepsremaining -= 1
end
#XXX record daily displacement?
# die once the lifespan has been reached
if self.age >= sum(self.daysinphase)
recordlifestats(self, model)
@kill()
end
end
......@@ -210,6 +223,56 @@ function suitablehabitat(butterfly::MarbledWhite, model::SimulationModel, pos::T
@cropheight() <= butterfly.maxheight)))
end
"""
recordmovementstats(butterfly, model)
Record the habitat category of the butterfly's current location in its life stats.
"""
function recordmovementstats(butterfly::MarbledWhite, model::SimulationModel)
pos = butterfly.pos
if @cropname() == "permanent grassland (low yield)"
butterfly.lifestats["Extensive grassland"] +=1
elseif @cropname() == "permanent grassland (grazed)"
butterfly.lifestats["Intensive grassland"] +=1
elseif @cropname() == "set-aside"
butterfly.lifestats["Fallow"] +=1
elseif @cropname() == ""
if @landcover() == "grass"
butterfly.lifestats["Unmanaged grassland"] +=1
else
butterfly.lifestats["Other"] +=1
end
else
butterfly.lifestats["Arable"] += 1
end
end
"""
recordlifestats(butterfly, model)
Save this butterfly's life stats to file.
"""
function recordlifestats(butterfly::MarbledWhite, model::SimulationModel)
stats = butterfly.lifestats
totalmovement = stats["Unmanaged grassland"] + stats["Extensive grassland"] +
stats["Fallow"] + stats["Intensive grassland"] +
stats["Arable"] + stats["Other"]
# use Pythagoras to calculate the lifetime displacement
displacement = round(sqrt(sum(abs.(butterfly.birthplace .- butterfly.pos).^2)))
record!(model, "marbledwhite_lifestats",
[butterfly.id,
stats["Fecundity"],
# save average daily movement and lifetime displacement distances (but strip out units)
Int(round((totalmovement/butterfly.daysinphase[4]))*@param(world.mapresolution)/1m),
Int(displacement*@param(world.mapresolution)/1m),
# save percentage time spent in different habitats
Int(round(stats["Unmanaged grassland"]/totalmovement*100)),
Int(round(stats["Extensive grassland"]/totalmovement*100)),
Int(round(stats["Fallow"]/totalmovement*100)),
Int(round(stats["Intensive grassland"]/totalmovement*100)),
Int(round(stats["Arable"]/totalmovement*100)),
Int(round(stats["Other"]/totalmovement*100))])
end
## INITIALISATION
......@@ -238,15 +301,16 @@ random, but I don't have data for that.)
if self.enforceflyingperiod
eclose = self.birthdate+Day(self.daysinphase[1]+self.daysinphase[2]+self.daysinphase[3])
if eclose < self.earliesteclosure
diff = @thisyear(self.earliesteclosure) - eclose
diff = @nextyear(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 - @thisyear(self.latesteclosure)
diff = eclose - @nextyear(self.latesteclosure)
self.daysinphase[2] -= diff.value
@debug("Reduced larval time by $(diff) to stay in flying period.")
end
end
self.birthplace = self.pos
end
"""
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment