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

Adaptations to marbled white model

In the process of validation here...
parent 18343090
No related branches found
No related tags found
No related merge requests found
name = "Persefone"
uuid = "039acd1d-2a07-4b33-b082-83a1ff0fd136"
authors = ["Daniel Vedder <daniel.vedder@idiv.de>"]
version = "0.7.0"
version = "0.8.0beta"
[deps]
AquaCrop = "8f16cebd-c0b4-44a3-857f-c101f083256c"
......
......@@ -59,7 +59,7 @@ function populationtrends(model::SimulationModel)
pops = @data("populations")
ncolors = max(2, length(@param(nature.targetspecies)))
update_theme!(palette=(color=cgrad(:seaborn_bright, ncolors),), cycle=[:color])
f = Figure()
f = Figure(size=(1600,800))
dates = @param(core.startdate):@param(core.enddate)
axlimits = (1, length(dates), 0, max(MIN_AXISLIMIT, maximum(pops[!,:Abundance]; init=0)*1.1))
ax = Axis(f[1,1], xlabel="Date", ylabel="Population size",
......@@ -144,7 +144,7 @@ Returns a Makie figure object.
function marbledwhitepopulation(model::SimulationModel)
!("MarbledWhite" in @param(nature.targetspecies)) && return nothing
pops = @data("marbledwhite_abundance")
f = Figure()
f = Figure(size=(1600,800))
dates = @param(core.startdate):@param(core.enddate)
axlimits = (1, length(dates), 0, max(MIN_AXISLIMIT, maximum(pops[!,:TotalAbundance]; init=0)))
ax = Axis(f[1,1], xlabel="Date", ylabel="Population size",
......@@ -165,13 +165,12 @@ Plot various statistics from the marbled white model: fecundity, movement, habit
"""
function marbledwhitelifestats(model::SimulationModel)
!("MarbledWhite" in @param(nature.targetspecies)) && return nothing
f = Figure(size=(1500,800))
f = Figure(size=(1600,800))
data = @data("marbledwhite_lifestats")
n = length(data[!, "ID"])
# fecundity
# fecundity / population density / displacement
violin(f[1,1], repeat([1], n), data[!, "Fecundity"], axis=(ylabel="Eggs/Female", xticks=([1], [""]), title="Fecundity"))
# movement / displacement
violin(f[1,2], repeat([1], n), data[!, "Daily movement"], axis=(ylabel="Meters", xticks=([1], [""]), title="Mean daily movement"))
violin(f[1,2], repeat([1], n), data[!, "Population density"], axis=(ylabel="Individuals/Hectare", xticks=([1], [""]), title="Population density"))
violin(f[1,3], repeat([1], n), data[!, "Displacement"]./1000, axis=(ylabel="Kilometers", xticks=([1], [""]), title="Lifetime displacement"))
# habitat use
boxplot(f[2,1:3], repeat(1:6, n), collect(Iterators.flatten(zip(data[!, "Unmanaged grassland"],
......
......@@ -138,9 +138,10 @@ function initmarbledwhitedata(model::SimulationModel)
["Date", "TotalAbundance", "Eggs", "Larvae", "Pupae", "Adults"],
@param(nature.popoutfreq), marbledwhiteabundance, marbledwhitepopulation)
newdataoutput!(model, "marbledwhite_lifestats",
["ID", "Year", "Fecundity", "Daily movement", "Displacement", "Unmanaged grassland",
"Extensive grassland", "Fallow", "Intensive grassland", "Arable", "Other"],
@param(nature.popoutfreq), nothing, marbledwhitelifestats) #TODO add
["ID", "Year", "Fecundity", "Population density",
"Displacement", "Unmanaged grassland", "Extensive grassland",
"Fallow", "Intensive grassland", "Arable", "Other"],
@param(nature.popoutfreq), nothing, marbledwhitelifestats)
end
"""
......
......@@ -51,26 +51,26 @@
# 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)
const mintemp = 17 # minimum temperature for activity (°C)
const maxtemp = 31 # maximum temperature for activity (°C)
# movement parameters
#FIXME these are arbitrary guesses!
const maxstepsperday = 80 # daily movement steps under optimal temperatures
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)
const socialdistancing = true # avoid pixels already occupied by conspecifics
const socialdistancing = false #true # avoid pixels already occupied by conspecifics
# lifecycle parameters
# (eggsperday and time parameters from Reinhardt et al. 2007)
const maxeggsperday = 7 # number of eggs laid under optimal conditions #TODO recalculate
const maxeggsperday = 6 # 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 maxadulttime = 34 # maximum lifespan in days as adult #XXX Reinhardt et al. say 17-34
const maturationtime = 5:8 # days from hatching to first oviposition
const juvenilemortality = 0.9 #0:25 # in percent (Wilson 1985, Dennis 1992) #TODO check up
const juvenilemortality = 0.98 #0:25 # in percent (Wilson 1985, Dennis 1992) #TODO check up
const mowingmortality = 0.3 # juvenile mortality from mowing events
const earliesteclosure::AnnualDate = (June, 15) # (Ebert & Rennwald 1991)
const latesteclosure::AnnualDate = (August, 15) # (Ebert & Rennwald 1991)
......@@ -85,8 +85,10 @@
timetomaturity::Int64 = 0 # is redefined in @create
# 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)
lifestats::Dict{String,Int64} = Dict("Fecundity"=>0, "Neighbours"=>0,
"Unmanaged grassland"=>0, "Fallow"=>0,
"Extensive grassland"=>0, "Arable"=>0,
"Intensive grassland"=>0, "Other"=>0)
end
......@@ -166,6 +168,7 @@ weather data.
end
end
# movement
#FIXME butterflies drift west, ending up on a lot of arable land
path::Vector{Tuple{Int64,Int64}} = [pos]
width, height = size(model.landscape)
while stepsremaining > 0
......@@ -189,14 +192,15 @@ weather data.
(c in path && @chance(self.selfavoidance)) && continue
(!suitablehabitat(self, model, c) && @chance(self.habitatpreference)) && continue
# move to the new location and record habitat stats
radius = self.perception / @param(world.mapresolution) # end the outer loop
@move(c)
recordmovementstats(self, model)
radius = Inf # end the outer loop
break
end
radius += 1
end
# lay an egg if possible
#XXX butterflies lay fewer eggs when they get older, see Gotthard et al. 2007
if eggsremaining > 0 && suitablehabitat(self, model, pos)
if @chance(1-self.juvenilemortality)
@reproduce() # only create an individual that will survive to adulthood
......@@ -266,13 +270,14 @@ function recordlifestats(butterfly::MarbledWhite, model::SimulationModel)
totalmovement = stats["Unmanaged grassland"] + stats["Extensive grassland"] +
stats["Fallow"] + stats["Intensive grassland"] +
stats["Arable"] + stats["Other"]
iszero(totalmovement) && (totalmovement = 1) # avoid division-by-zero below
# use Pythagoras to calculate the lifetime displacement
displacement = round(sqrt(sum(abs.(butterfly.birthplace .- butterfly.pos).^2)))
record!(model, "marbledwhite_lifestats",
[butterfly.id, Year(model.date),
stats["Fecundity"],
# save average daily movement and lifetime displacement distances (but strip out units)
Int(round((totalmovement/butterfly.daysinphase[4]))*@param(world.mapresolution)/1m),
# save current population density and lifetime displacement distances (but strip out units)
countanimals(butterfly.pos, model, radius=500m, species="MarbledWhite"),
Int(displacement*@param(world.mapresolution)/1m),
# save percentage time spent in different habitats
Int(round(stats["Unmanaged grassland"]/totalmovement*100)),
......@@ -299,13 +304,13 @@ random, but I don't have data for that.)
else
self.birthdate = model.date
if model.date <= self.earliesteclosure &&
model.date >= (self.latesteclosure + Day(maximum(self.adulttime)))
model.date >= (self.latesteclosure + Day(self.maxadulttime))
@warn("$(animalid(self)) born outside of flying period.")
end
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)]
@randn(self.pupatime), @rand(1:self.maxadulttime)]
# check whether eclosure is during the flight period, change the larval time if not
if self.enforceflyingperiod
eclose = self.birthdate+Day(self.daysinphase[1]+self.daysinphase[2]+self.daysinphase[3])
......@@ -334,7 +339,6 @@ Initialise the marbled white population with one individual on every grassland p
birthphase = egg
#popsize = 200 #FIXME use something else
indarea = 1ha # initialise 1 individual per 100 suitable pixels #XXX
#popsize = -1 # one individual per suitable location
sex = female #TODO change to hermaphrodite to force all individuals to have the same sex
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment