Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
Persefone.jl
Manage
Activity
Members
Plan
Wiki
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Locked files
Deploy
Package registry
Model registry
Operate
Terraform modules
Analyze
Contributor analytics
Repository analytics
Insights
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Persefone
Persefone.jl
Commits
402fa8e4
Commit
402fa8e4
authored
11 months ago
by
xo30xoqa
Browse files
Options
Downloads
Patches
Plain Diff
Finished implementing the Skylark :D
Closes #9. Still needs testing & validation.
parent
5d3cb400
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
src/crop/farmplot.jl
+5
-5
5 additions, 5 deletions
src/crop/farmplot.jl
src/nature/species/skylark.jl
+55
-34
55 additions, 34 deletions
src/nature/species/skylark.jl
with
60 additions
and
39 deletions
src/crop/farmplot.jl
+
5
−
5
View file @
402fa8e4
...
...
@@ -192,23 +192,23 @@ end
"""
cropheight(model, position)
Return the height of the crop at this position, or
nothing
if there is no crop here
Return the height of the crop at this position, or
0
if there is no crop here
(utility wrapper).
"""
function
cropheight
(
pos
::
Tuple
{
Int64
,
Int64
},
model
::
SimulationModel
)
ismissing
(
model
.
landscape
[
pos
...
]
.
fieldid
)
?
0
cm
:
#FIXME
should not retur
n 0
model
.
farmplots
[
model
.
landscape
[
pos
...
]
.
fieldid
]
.
height
ismissing
(
model
.
landscape
[
pos
...
]
.
fieldid
)
?
0
cm
:
#FIXME
can I return something better tha
n 0
?
model
.
farmplots
[
model
.
landscape
[
pos
...
]
.
fieldid
]
.
height
*
1
cm
#FIXME units
end
"""
cropcover(model, position)
Return the percentage ground cover of the crop at this position, or
nothing
if there is no crop
Return the percentage ground cover of the crop at this position, or
0
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
)
?
0
:
#FIXME
should not retur
n 0
ismissing
(
model
.
landscape
[
pos
...
]
.
fieldid
)
?
0
:
#FIXME
can I return something better tha
n 0
?
model
.
farmplots
[
model
.
landscape
[
pos
...
]
.
fieldid
]
.
LAItotal
end
This diff is collapsed.
Click to expand it.
src/nature/species/skylark.jl
+
55
−
34
View file @
402fa8e4
...
...
@@ -35,13 +35,12 @@ At the moment, this implementation is still in development.
const
visionrange
::
Length
=
200
m
#XXX arbitrary
const
eggtime
::
Int64
=
11
# days from laying to hatching
const
nestlingtime
::
UnitRange
{
Int64
}
=
7
:
11
# days from hatching to leaving nest
const
fledglingtime
::
UnitRange
{
Int64
}
=
2
5
:
30
# days from
hatching
to independence
const
nestlingtime
::
Int64
=
9
# days from hatching to leaving nest
const
fledglingtime
::
Int64
=
2
1
# days from
leaving the nest
to independence
#XXX predation mortality should be habitat-dependent
const
eggpredationmortality
::
Float64
=
0.03
# per-day egg mortality from predation
const
nestharvestmortality
::
Float64
=
1.0
# egg/nestling mortality after a harvest event
const
nestlingpredationmortality
::
Float64
=
0.03
# per-day nestling mortality from predation
const
fledglingharvestmortality
::
Float64
=
0.5
# fledgling mortality after harvest
const
fledglingpredationmortality
::
Float64
=
0.01
# per-day fledgling mortality from predation
const
firstyearmortality
::
Float64
=
0.38
# total mortality in the first year after independence
const
migrationmortality
::
Float64
=
0.33
# chance of dying during the winter
...
...
@@ -57,17 +56,14 @@ At the moment, this implementation is still in development.
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
eggsperclutch
::
UnitRange
{
Int64
}
=
2
:
5
# eggs laid per clutch
const
breedingdelay
::
Int64
=
18
# days after hatching before starting a new brood #XXX ??
const
nestingend
::
Int64
=
July
# last month of nesting
# individual variables
#FIXME check what needs to be rewritten
timer
::
Int64
=
0
# a count-down timer that can be used for different purposes
timer
::
Int64
=
0
# a counter that can be used for different purposes
migrationdates
::
Tuple
=
()
# is defined by each individual in @create(Skylark)
mate
::
Int64
=
-
1
# the agent ID of the mate (-1 if none)
nest
::
Tuple
=
()
# coordinates of current nest
nestcompletion
::
Int64
=
0
# days left until the nest is built
clutch
::
Int64
=
0
# number of offspring in current clutch
clutch
::
Int64
=
0
# number and life stage of offspring in current clutch
end
...
...
@@ -203,8 +199,8 @@ Females that have found a partner build a nest and lay eggs in a suitable locati
self
.
timer
-=
1
end
# tillage and harvest destroys the nest
@respond
(
tillage
,
self
.
nest
=
(
))
@respond
(
harvesting
,
self
.
nest
=
(
))
@respond
(
tillage
,
destroynest!
(
self
,
"tillage"
))
@respond
(
harvesting
,
destroynest!
(
self
,
"harvesting"
))
end
"""
...
...
@@ -212,12 +208,32 @@ Females that have laid eggs take care of their chicks, restarting the nesting pr
chicks are independent or in case of brood loss.
"""
@phase
Skylark
breeding
begin
#TODO wait for eggs to hatch & chicks to mature, checking for mortality
# restart breeding cycle if there is time
if
self
.
clutch
==
0
&&
month
(
model
.
date
)
<=
self
.
nestingend
@setphase
(
nesting
)
#TODO breeding delay?
elseif
month
(
model
.
date
)
>
self
.
nestingend
@setphase
(
nonbreeding
)
#XXX Schachtelbruten - sometimes skylarks start a new nest before the previous young are gone
# wait for eggs to hatch & chicks to mature, checking for predation and disturbance mortality
self
.
timer
+=
1
#XXX this should be habitat-dependent!
if
self
.
timer
<=
self
.
eggtime
@chance
(
self
.
eggpredationmortality
)
&&
destroynest!
(
self
,
"predation"
)
elseif
self
.
timer
<=
self
.
eggtime
+
self
.
nestlingtime
@chance
(
self
.
nestlingpredationmortality
)
&&
destroynest!
(
self
,
"predation"
)
elseif
self
.
timer
<=
self
.
eggtime
+
self
.
nestlingtime
+
self
.
fledglingtime
@chance
(
self
.
fledglingpredationmortality
)
&&
destroynest!
(
self
,
"predation"
)
else
# create new young, reset timer and clutch counter
@reproduce
(
self
.
clutch
,
self
.
mate
)
self
.
clutch
=
0
end
if
self
.
clutch
>
0
# tillage and harvest destroys the nest
@respond
(
tillage
,
destroynest!
(
self
,
"tillage"
))
@respond
(
harvesting
,
destroynest!
(
self
,
"harvesting"
))
else
# restart breeding cycle if there is time
self
.
timer
=
0
if
month
(
model
.
date
)
<=
self
.
nestingend
@setphase
(
nesting
)
elseif
month
(
model
.
date
)
>
self
.
nestingend
@setphase
(
nonbreeding
)
end
end
end
...
...
@@ -236,8 +252,8 @@ function migrationdates(skylark::Skylark, model::SimulationModel)
minarrive
=
skylark
.
sex
==
male
?
(
February
,
15
)
:
(
March
,
1
)
deltaleave
=
@rand
(
0
:
45
)
#XXX ought to be normally distributed
deltaarrive
=
@rand
(
0
:
15
)
#XXX ought to be normally distributed
leave
=
Date
(
year
(
model
.
date
),
minleave
[
1
],
minleave
[
2
])
+
Day
(
deltaleave
)
)
arrive
=
Date
(
year
(
model
.
date
)
+
1
,
minarrive
[
1
],
minarrive
[
2
])
+
Day
(
deltaarrive
)
)
leave
=
Date
(
year
(
model
.
date
),
minleave
[
1
],
minleave
[
2
])
+
Day
(
deltaleave
)
arrive
=
Date
(
year
(
model
.
date
)
+
1
,
minarrive
[
1
],
minarrive
[
2
])
+
Day
(
deltaarrive
)
(
leave
,
arrive
)
end
...
...
@@ -292,7 +308,9 @@ end
foragequality(skylark, model, pos)
Calculate the relative quality of the habitat at this position for foraging.
(Approximated from Püttmanns et al., 2021; Jeromin, 2002; Jenny, 1990b.)
This assumes that open habitat is best (quality = 1.0), and steadily decreases as vegetation
height and/or cover increase. (Linear regressions based on Püttmanns et al., 2021; Jeromin, 2002;
Jenny, 1990b.)
"""
function
foragequality
(
skylark
::
Skylark
,
model
::
SimulationModel
,
pos
::
Tuple
{
Int64
,
Int64
})
#TODO this is a key function that needs to be validated thoroughly
...
...
@@ -301,18 +319,9 @@ function foragequality(skylark::Skylark, model::SimulationModel, pos::Tuple{Int6
(
@distanceto
(
builtup
)
<
skylark
.
mindistancetoedge
)
return
0.0
end
quality
=
1.0
f
=
farmplot
(
pos
,
model
)
# Assume that grass and soil have a habitat quality of 1.0. For fields, calculate quality
# as the sum of cover quality and height quality (each modelled using a linear regression).
if
!
isnothing
(
f
)
groundcoverfactor
=
x
->
bounds
((
-
1
/
skylark
.
maxforagecover
)
*
x
+
1.0
,
max
=
1.0
)
plantheightfactor
=
x
->
bounds
((
-
1
/
skylark
.
maxforageheight
)
*
(
x
|>
cm
)
+
1.0
,
max
=
1.0
)
#FIXME need percentage cover in FarmPlot, not LAI
#FIXME height is currently dimensionless in FarmPlot, hence the conversion to cm
quality
=
bounds
(
groundcoverfactor
(
f
.
LAItotal
)
+
plantheightfactor
(
f
.
height
*
1
cm
),
max
=
1.0
)
end
return
quality
groundcoverfactor
=
x
->
bounds
((
-
1
/
skylark
.
maxforagecover
)
*
x
+
1.0
,
max
=
1.0
)
plantheightfactor
=
x
->
bounds
((
-
1
/
skylark
.
maxforageheight
)
*
(
x
|>
cm
)
+
1.0
,
max
=
1.0
)
return
bounds
(
groundcoverfactor
(
@cropcover
())
+
plantheightfactor
(
@cropheight
()),
max
=
1.0
)
end
"""
...
...
@@ -324,12 +333,24 @@ function allowsnesting(skylark::Skylark, model::SimulationModel, pos::Tuple{Int6
#TODO is this condition correct? -> needs validation!
(
@landcover
()
==
grass
||
(
@landcover
()
==
agriculture
&&
(
skylark
.
nestingheight
[
1
]
<=
@cropheight
()
<=
skylark
.
nestingheight
[
2
])
&&
(
skylark
.
nestingheight
[
1
]
<=
(
@cropheight
()
)
<=
skylark
.
nestingheight
[
2
])
&&
(
skylark
.
nestingcover
[
1
]
<=
@cropcover
()
<=
skylark
.
nestingcover
[
2
])))
#&&
#FIXME if we add the distance requirement, females don't find a nesting spot?
#(@distanceto(forest) < skylark.mindistancetoedge) &&
#(@distanceto(builtup) < skylark.mindistancetoedge)
end
"""
destroynest!(skylark, reason)
Remove the skylark's nest and offspring due to disturbance or predation.
"""
function
destroynest!
(
self
::
Skylark
,
reason
::
String
)
self
.
nest
=
()
self
.
clutch
=
0
@debug
(
"
$
(animalid(self)) had her nest destroyed by
$
reason."
)
end
## INITIALISATION
"""
...
...
@@ -345,7 +366,7 @@ should currently be on migration. Also sets other individual-specific variables.
@setphase
(
territorysearch
)
:
@setphase
(
matesearch
)
@migrate
(
arrive
)
self
.
migrationdates
=
self
.
migrationdates
.+
Year
(
1
)
)
self
.
migrationdates
=
self
.
migrationdates
.+
Year
(
1
)
end
end
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment