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

Implemented a basic skylark species

Major commit - not yet quite functional
parent 36f8a06f
Branches
Tags
No related merge requests found
......@@ -11,54 +11,195 @@ At the moment, this implementation is still in development.
**Sources:**
- Bauer, H.-G., Bezzel, E., & Fiedler, W. (Eds.). (2012).
Das Kompendium der Vögel Mitteleuropas: Ein umfassendes
Handbuch zu Biologie, Gefährdung und Schutz (Einbändige
Sonderausg. der 2., vollständig überarb. und erw. Aufl. 2005).
AULA-Verlag
Das Kompendium der Vögel Mitteleuropas: Ein umfassendes
Handbuch zu Biologie, Gefährdung und Schutz (Einbändige
Sonderausg. der 2., vollständig überarb. und erw. Aufl. 2005).
AULA-Verlag
- Glutz von Blotzheim, Urs N. (Ed.). (1985). Handbuch der
Vögel Mitteleuropas. Bd. 10. Passeriformes (Teil 1)
1. Alaudidae - Hirundidae. AULA-Verlag, Wiesbaden.
ISBN 3-89104-019-9
"""
@species Skylark begin
eggmaturationtime = 11
eggharvestmortality = 0.9 #???
eggpredationmortality = 0.1 #???
eggtime = 11 # 11 days from laying to hatching
eggpredationmortality = 0.03 # per-day egg mortality from predation
nestharvestmortality = 0.9 # egg mortality after a harvest event (XXX guess)
migrationdates = ()
nestlingtime = 7:11 # 7-11 days from hatching to leaving nest
nestlingpredationmortality = 0.03 # per-day nestling mortality from predation
habitats = @habitat((@landcover() == grass ||
fledglingtime = 25:30 # 25-30 days from hatching to independence
fledglingharvestmortality = 0.5 # fledgling mortality after harvest
fledglingpredationmortality = 0.01 # per-day fledgling mortality from predation
firstyearmortality = 0.38 # total mortality in the first year after independence
migrationdates = () # is defined by each individual in `initskylark()`
migrationmortality = 0.33 # chance of dying during the winter
mate = -1 # the agent ID of the mate (-1 if none)
nest = () # coordinates of current nest
nestingbegin = (4, 10) # begin nesting in the middle of April
nestbuildingtime = 4:5 # 4-5 days needed to build a nest (doubled for first nest)
nestcompletion = 0 # days left until the nest is built
eggsperclutch = 2:5 # 2-5 eggs laid per clutch
clutch = [] # IDs of offspring in current clutch
breedingdelay = 18 # wait 18 days after hatching to start a new brood
habitats = @habitat((@landcover() == grass ||
# settle on grass or arable land (but not maize)
(@landcover() == agriculture && @cropname() != "maize")) &&
@distanceto(forest) > 5)
@distancetoedge() > 5) # at least 50m from other habitats
#XXX this ought to check for distance to forest and builtup,
# but that's very expensive (see below)
# @distanceto(forest) > 5 && # at least 50m from forest edges
# @distanceto(builtup) > 5) # and from anthropogenic structures
@initialise(habitats, pairs=true, initfunction=initskylark)
@initialise(habitats, popdensity=300, pairs=true, initfunction=initskylark)
"""
As an egg, simply check for mortality and hatching.
"""
@phase egg begin
@kill(@trait(eggpredationmortality), "predation")
@respond harvest @kill(@trait(eggharvestmortality), "harvest")
#TODO dies if parents die (due to starvation?)
@respond(harvesting, @kill(@trait(nestharvestmortality), "harvest"))
if @trait(age) == 14
if @trait(age) == @trait(eggtime)
@setphase(nestling)
end
end
"""
As a nestling, simply check for mortality and fledging.
"""
@phase nestling begin
#TODO
#TODO add feeding & growth
@kill(@trait(nestlingpredationmortality), "predation")
@respond(harvesting, @kill(@trait(nestharvestmortality), "harvest"))
if @trait(age) == @trait(nestlingtime)+@trait(eggtime)
@setphase(fledgling)
end
end
@phase breeding begin
#TODO
"""
As a fledgling, move around a little, but mainly wait for maturity and
check mortality.
"""
@phase fledgling begin
#TODO add feeding & growth
@kill(@trait(fledglingpredationmortality), "predation")
@randomwalk(1) #TODO add movement following the parents
if @trait(age) == @trait(fledglingtime)+@trait(eggtime)
@kill(@trait(firstyearmortality), "first year mortality") #XXX mechanistic?
@setphase(nonbreeding)
end
end
"""
As a non-breeding adult, move around with other individuals and check for migration.
"""
@phase nonbreeding begin
#TODO
# flocking behaviour - follow a random neighbour or move randomly
#TODO add feeding and mortality, respect habitat when moving
neighbours = map(a->a.id, @neighbours(10))
#isempty(neighbours) ? @randomwalk(5) : @follow(@rand(neighbours), 2)
if isempty(neighbours)
@randomwalk(5)
else
@follow(model[@rand(neighbours)], 2)
end
# check if the bird migrates
leave, arrive = animal.migrationdates
m, d = monthday(model.date)
migrate = (((m < arrive[1]) || (m == arrive[1] && d < arrive[2])) ||
((m > leave[1]) || (m == leave[1] && d >= leave[2])))
if migrate
@kill(@trait(migrationmortality), "migration")
returndate = Date(year(model.date), arrive[1], arrive[2])
model.date != @param(core.startdate) && (returndate += Year(1))
@setphase(mating)
@migrate(returndate)
end
end
@phase migration begin
#TODO
"""
Move around until a mate is found.
"""
@phase mating begin
# if we've found a mate, wait for nesting begin and then go to the next phase
if @trait(mate) != -1
if !@isalive(@trait(mate))
@trait(mate) = -1
return
end
m, d = monthday(model.date)
nest = ((m == @trait(nestingbegin)[1] && d > @trait(nestingbegin)[2]
&& @chance(0.05)) || (m > @trait(nestingbegin)[1]))
nest && @setphase(nestbuilding)
return
end
# look for a mate among the neighbouring birds, or move randomly
for n in @neighbours(50)
if n.sex != @trait(sex) && n.mate == -1
@trait(mate) = n.id
n.mate = @trait(id)
@debug "$(animalid(@trait(id))) and $(animalid(n.id)) have mated."
return
end
end
@randomwalk(10)
end
@phase mating begin
#TODO
"""
Females select a location and build a nest. Males do nothing. (Sound familiar?)
"""
@phase nestbuilding begin
if @trait(sex) == female
if isempty(@trait(nest))
# try to find a nest in the neighbourhood, or move on
nest = @randompixel(10, @trait(habitats))
if isnothing(nest)
nest = ()
@randomwalk(20)
else
# if we've found a location, start the clock on the building time
# (building time doubles for the first nest of the year)
@trait(nestcompletion) = @rand(nestbuildingtime)
month(model.date) == 4 && (@trait(nestcompletion) *= 2)
end
else
# wait while nest is being built, then lay eggs and go to next phase
if @trait(nestcompletion) > 0
@trait(nestcompletion) -= 1
else
@trait(clutch) = @reproduce(@trait(mate), @rand(eggsperclutch))
@animal(@trait(mate)).clutch = @trait(clutch)
@setphase(breeding)
end
end
else
# males stay near the female
@follow(model[@trait(mate)], 5)
@animal(@trait(mate)).phase == "breeding" && @setphase(breeding)
end
end
"""
Do lots of foraging (not yet implemented).
"""
@phase breeding begin
#TODO forage (move random)
for offspring in @trait(clutch)
# check if offspring are still alive and juvenile, else remove from clutch
if !@isalive(offspring) || @animal(offspring).phase == "nonbreeding"
deleteat!(@trait(clutch), findfirst(x->x==offspring, @trait(clutch)))
end
end
# if all young have fledged, move to nonbreeding (if it's July) or breed again
if isempty(@trait(clutch))
@trait(nest) = ()
month(model.date) >= 7 ? @setphase(nonbreeding) : @setphase(nestbuilding)
end
end
end
......@@ -66,13 +207,14 @@ end
initskylark(skylark, model)
Initialise a skylark individual. Selects migration dates and checks if the
bird should currently be on migration.
bird should currently be on migration. Also sets other individual-specific
variables. Called at model initialisation and when an egg is laid.
"""
function initskylark(animal::Animal, model::AgentBasedModel)
@debug "Added $(animalid(animal)) at $(animal.pos)"
# calculate migration dates for this individual
animal.migrationdates = migrationdates(animal, model)
leave = animal.migrationdates[1]
arrive = animal.migrationdates[2]
leave, arrive = animal.migrationdates
m, d = monthday(model.date)
migrate = (((m < arrive[1]) || (m == arrive[1] && d < arrive[2])) ||
((m > leave[1]) || (m == leave[1] && d >= leave[2])))
......@@ -81,6 +223,9 @@ function initskylark(animal::Animal, model::AgentBasedModel)
model.date != @param(core.startdate) && (returndate += Year(1))
@migrate(returndate)
end
# set individual life-history parameters that are defined as ranges for the species
@trait(nestlingtime) = @rand(@trait(nestlingtime))
@trait(fledglingtime) = @rand(@trait(fledglingtime))
#TODO other stuff?
end
......@@ -91,6 +236,8 @@ Select the dates on which this skylark will leave for / return from its migratio
based on observed migration patterns.
"""
function migrationdates(skylark::Animal, model::AgentBasedModel)
#TODO this ought to be temperature-dependent and dynamic
#XXX magic numbers!
minleave = skylark.sex == female ? (9, 15) : (10, 1)
minarrive = skylark.sex == male ? (2, 15) : (3, 1)
deltaleave = @rand(0:45) #XXX ought to be normally distributed
......@@ -99,3 +246,4 @@ function migrationdates(skylark::Animal, model::AgentBasedModel)
arrive = monthday(Date(2001, minarrive[1], minarrive[2]) + Day(deltaarrive))
(leave, arrive)
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment