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

Wrote skylark nesting phase

parent 99fafcf3
No related branches found
No related tags found
No related merge requests found
...@@ -69,10 +69,14 @@ export ...@@ -69,10 +69,14 @@ export
@killother, @killother,
@reproduce, @reproduce,
@migrate, @migrate,
@occupy,
@isoccupied,
@vacate,
@habitat, @habitat,
@landcover, @landcover,
@cropname, @cropname,
@cropheight, @cropheight,
@cropcover,
@directionto, @directionto,
@distanceto, @distanceto,
@distancetoedge, @distancetoedge,
......
...@@ -199,3 +199,16 @@ function cropheight(pos::Tuple{Int64,Int64}, model::SimulationModel) ...@@ -199,3 +199,16 @@ function cropheight(pos::Tuple{Int64,Int64}, model::SimulationModel)
ismissing(model.landscape[pos...].fieldid) ? nothing : ismissing(model.landscape[pos...].fieldid) ? nothing :
model.farmplots[model.landscape[pos...].fieldid].height model.farmplots[model.landscape[pos...].fieldid].height
end end
"""
cropcover(model, position)
Return the percentage ground cover of the crop at this position, or nothing if there is no crop
here (utility wrapper).
"""
function cropcover(pos::Tuple{Int64,Int64}, model::SimulationModel)
#FIXME LAItotal != ground cover?
ismissing(model.landscape[pos...].fieldid) ? nothing :
model.farmplots[model.landscape[pos...].fieldid].LAItotal
end
...@@ -348,7 +348,7 @@ end ...@@ -348,7 +348,7 @@ end
""" """
@cropheight @cropheight
Return the height of the crop at this position, or 0 if there is no crop here. Return the height of the crop at this position, or nothing if there is no crop here.
This is a utility wrapper that can only be used nested within [`@phase`](@ref) This is a utility wrapper that can only be used nested within [`@phase`](@ref)
or [`@habitat`](@ref). or [`@habitat`](@ref).
""" """
...@@ -356,6 +356,17 @@ macro cropheight() ...@@ -356,6 +356,17 @@ macro cropheight()
:(cropheight($(esc(:pos)), $(esc(:model)))) :(cropheight($(esc(:pos)), $(esc(:model))))
end end
"""
@cropcover
Return the percentage ground cover of the crop at this position, or nothing if there is no crop
here. This is a utility wrapper that can only be used nested within [`@phase`](@ref)
or [`@habitat`](@ref).
"""
macro cropcover()
:(cropcover($(esc(:pos)), $(esc(:model))))
end
""" """
@directionto @directionto
...@@ -468,6 +479,7 @@ used nested within [`@phase`](@ref). ...@@ -468,6 +479,7 @@ used nested within [`@phase`](@ref).
macro walk(args...) macro walk(args...)
#XXX add `ifempty` keyword? #XXX add `ifempty` keyword?
:(walk!($(esc(:self)), $(esc(:model)), $(map(esc, args)...))) :(walk!($(esc(:self)), $(esc(:model)), $(map(esc, args)...)))
#FIXME MethodError: no method matching walk!(::Persefone.Skylark, ::AgricultureModel, ::Tuple{UnitRange{Int64}, UnitRange{Int64}}) -> due to map(esc())?
end end
#TODO add own walking functions that respect habitat descriptors #TODO add own walking functions that respect habitat descriptors
......
...@@ -31,8 +31,8 @@ At the moment, this implementation is still in development. ...@@ -31,8 +31,8 @@ At the moment, this implementation is still in development.
""" """
@species Skylark begin @species Skylark begin
# species parameters # species parameters
const movementrange = 500m #XXX arbitrary const movementrange::Length = 500m #XXX arbitrary
const visionrange = 200m #XXX arbitrary const visionrange::Length = 200m #XXX arbitrary
const eggtime::Int64 = 11 # days from laying to hatching const eggtime::Int64 = 11 # days from laying to hatching
const nestlingtime::UnitRange{Int64} = 7:11 # days from hatching to leaving nest const nestlingtime::UnitRange{Int64} = 7:11 # days from hatching to leaving nest
...@@ -55,7 +55,7 @@ At the moment, this implementation is still in development. ...@@ -55,7 +55,7 @@ At the moment, this implementation is still in development.
const nestingbegin::Tuple{Int64,Int64} = (April, 10) # begin nesting in the middle of April const nestingbegin::Tuple{Int64,Int64} = (April, 10) # begin nesting in the middle of April
const nestbuildingtime::UnitRange{Int64} = 4:5 # 4-5 days needed to build a nest (doubled for first nest) const nestbuildingtime::UnitRange{Int64} = 4:5 # 4-5 days needed to build a nest (doubled for first nest)
const eggsperclutch::UnitRange{Int64} = 2:5 # eggs laid per clutch const eggsperclutch::UnitRange{Int64} = 2:5 # eggs laid per clutch
const breedingdelay::Int64 = 18 # days after hatching before starting a new brood const breedingdelay::Int64 = 18 # days after hatching before starting a new brood #XXX ??
const nestingend::Int64 = July # last month of nesting const nestingend::Int64 = July # last month of nesting
# individual variables # individual variables
...@@ -74,7 +74,7 @@ end ...@@ -74,7 +74,7 @@ end
#TODO respect habitat when moving #TODO respect habitat when moving
""" """
As a non-breeding adult, move around with other individuals and check for migration. Non-breeding adults move around with other individuals and check for migration.
""" """
@phase Skylark nonbreeding begin @phase Skylark nonbreeding begin
# flocking behaviour - follow a random neighbour or move randomly # flocking behaviour - follow a random neighbour or move randomly
...@@ -91,27 +91,45 @@ As a non-breeding adult, move around with other individuals and check for migrat ...@@ -91,27 +91,45 @@ As a non-breeding adult, move around with other individuals and check for migrat
@kill(self.migrationmortality, "migration") @kill(self.migrationmortality, "migration")
returndate = Date(year(model.date)+1, arrive[1], arrive[2]) returndate = Date(year(model.date)+1, arrive[1], arrive[2])
self.sex == male ? self.sex == male ?
@setphase(territory-search) : @setphase(territorysearch) :
@setphase(mate-search) @setphase(matesearch)
@migrate(returndate) @migrate(returndate)
end end
end end
@phase Skylark territory-search begin """
#TODO move around, searching for a suitable area to establish a territory Males returning from migration move around to look for suitable habitats to establish a territory.
"""
@phase Skylark territorysearch begin
#TODO
#TODO Standorttreue
# If we've found a territory, or the breeding season is over, move to the next phase # If we've found a territory, or the breeding season is over, move to the next phase
if !isempty(self.territory) if !isempty(self.territory)
@setphase(occupation) @setphase(occupation)
elseif month(model.date) > nestingend elseif month(model.date) > self.nestingend
@setphase(nonbreeding) @setphase(nonbreeding)
else else
@walk("random", self.movementrange) @walk("random", self.movementrange)
#FIXME MethodError: no method matching walk!(::Persefone.Skylark, ::AgricultureModel, ::Tuple{UnitRange{Int64}, UnitRange{Int64}})
end end
end end
@phase Skylark mate-search begin """
Once a male has found a territory, he remains in it until the breeding season is over,
adjusting it to new conditions when and as necessary.
"""
@phase Skylark occupation begin
#move to a random location in the territory
@move(@rand(self.territory))
#TODO adjust territory as needed
end
"""
Females returning from migration move around to look for a suitable partner with a territory.
"""
@phase Skylark matesearch begin
#TODO move around, looking for a male with an established territory #TODO move around, looking for a male with an established territory
#TODO teilweise Partnertreue
# look for a mate among the neighbouring birds, or move randomly # look for a mate among the neighbouring birds, or move randomly
for n in @neighbours(self.visionrange) for n in @neighbours(self.visionrange)
...@@ -124,10 +142,7 @@ end ...@@ -124,10 +142,7 @@ end
end end
#@debug("$(animalid(self)) didn't find a mate.") #@debug("$(animalid(self)) didn't find a mate.")
if self.mate != -1 if self.mate != -1
mon, day = monthday(model.date) @setphase(nesting)
nest = ((mon == self.nestingbegin[1] && day >= self.nestingbegin[2]
&& @chance(0.1)) || (mon > self.nestingbegin[1])) #XXX magic number
nest && @setphase(breeding)
elseif month(model.date) > self.nestingend # stop trying to find a mate if it's too late elseif month(model.date) > self.nestingend # stop trying to find a mate if it's too late
@setphase(nonbreeding) @setphase(nonbreeding)
else else
...@@ -135,25 +150,60 @@ end ...@@ -135,25 +150,60 @@ end
end end
end end
@phase Skylark occupation begin """
#move to a random location in the territory Females that have found a partner build a nest and lay eggs in a suitable location.
@move(@rand(self.territory)) """
#TODO adjust territory as needed @phase Skylark nesting begin
if model.date < Date(year(model.date), self.nestingbegin...)
# wait for nesting to begin, moving around in the territory
@move(@rand(@animal(self.mate).territory))
elseif isempty(nest)
# choose site, build nest & lay eggs
for pos in @shuffle!(deepcopy(@animal(self.mate).territory))
#TODO is this condition correct? -> needs validation!
if (@landcover() == grass || @landcover() == soil ||
(@landcover() == agriculture &&
(self.nestingheight[1] <= @cropheight() <= self.nestingheight[2]) &&
(self.nestingcover[1] <= @cropcover() <= self.nestingcover[2])))
@move(pos)
self.nest = pos
self.clutch = @rand(self.eggsperclutch)
timer = self.nestbuildingtime + self.clutch # time to build + 1 day per egg laid
if month(model.date) == self.nestingbegin[1]
# the first nest takes twice as long to build
#XXX this may affect the first two nests
timer += self.nestbuildingtime
end
break
end
end
isempty(nest) && @warn("$(animalid(self)) didn't find a nesting location.")
elseif timer == 0
@debug("$(animalid(self)) has laid $(self.clutch) eggs.")
@setphase(breeding)
else
self.timer -= 1
end
# tillage and harvest destroys the nest
@respond(tillage, nest = ())
@respond(harvesting, nest = ())
end end
"""
Females that have laid eggs take care of their chicks, restarting the nesting process once the
chicks are independent or in case of brood loss.
"""
@phase Skylark breeding begin @phase Skylark breeding begin
if isempty(nest) #TODO wait for eggs to hatch & chicks to mature, checking for mortality
#TODO choose site, build nest & lay eggs # restart breeding cycle if there is time
elseif clutch > 0 if clutch == 0 && month(model.date) <= self.nestingend
#TODO wait for eggs to hatch & chicks to mature, checking for mortality @setphase(nesting) #TODO breeding delay?
elseif month(model.date) > self.nestingend elseif month(model.date) > self.nestingend
#TODO restart cycle, if time
@setphase(nonbreeding) @setphase(nonbreeding)
end end
end end
## SUPPORTING FUNCTIONS ## SUPPORTING FUNCTIONS
""" """
...@@ -215,8 +265,8 @@ should currently be on migration. Also sets other individual-specific variables. ...@@ -215,8 +265,8 @@ should currently be on migration. Also sets other individual-specific variables.
returndate = Date(year(model.date), arrive[1], arrive[2]) returndate = Date(year(model.date), arrive[1], arrive[2])
model.date != @param(core.startdate) && (returndate += Year(1)) model.date != @param(core.startdate) && (returndate += Year(1))
self.sex == male ? self.sex == male ?
@setphase(territory-search) : @setphase(territorysearch) :
@setphase(mate-search) @setphase(matesearch)
@migrate(returndate) @migrate(returndate)
end end
end end
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment