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

Simplified phase handling in @species

parent 3e33eefd
No related branches found
No related tags found
No related merge requests found
......@@ -61,6 +61,9 @@ function getsettings(configfile::String, seed::Union{Int64,Nothing}=nothing)
outdir = defaultoutdir*"_"*string(Dates.today())*"_s"*string(settings["core"]["seed"])
settings["core"]["outdir"] = outdir
end
if settings["core"]["startdate"] > settings["core"]["enddate"]
Base.error("Enddate is earlier than startdate.")
end
settings
end
......
......@@ -17,11 +17,10 @@ by trait dictionaries passed by them during initialisation.
"""
@agent Animal GridAgent{2} begin
#XXX is it (performance-)wise to use a dict for the traits?
# Doesn't this rather obviate the point of having an agent struct?
# Doesn't that rather obviate the point of having an agent struct?
traits::Dict{String,Any}
sex::Sex
age::Int32
#XXX keep track of parents and/or offspring?
end
"""
......@@ -71,7 +70,7 @@ custom syntax to describe species' biology:
```julia
@species name begin
@initialise!(phase1, @habitat(...))
@initialise!(@habitat(...))
speciesvar1 = 3.14
...
......@@ -95,6 +94,7 @@ macro species(name, body)
quote
Core.@__doc__ function $(esc(name))($(esc(:model))::AgentBasedModel)
$(esc(:name)) = string($(QuoteNode(name)))
$(esc(:phase)) = ""
$(esc(body))
vardict = Base.@locals
speciesdict = Dict{String,Any}()
......@@ -107,20 +107,17 @@ macro species(name, body)
end
"""
@initialise!(phase, habitatdescriptor; kwargs...)
@initialise!(habitatdescriptor; kwargs...)
Call this macro within the body of `@species`. It sets the phase that each individual
of this species will be assigned at birth, and passes the given habitat descriptor
Call this macro within the body of `@species`. It passes the given habitat descriptor
function and keyword arguments on to `initpopulation()` when setting up the simulation.
Note: if this macro is not used, `phase` and `initialise!` must be set manually in
the species definition.
Note: if this macro is not used, the variable `initialise!` must be set manually in the
species definition.
"""
macro initialise!(phase, habitatdescriptor, kwargs...)
quote
$(esc(:phase)) = String($phase)
$(esc(:initialise!)) = initpopulation($habitatdescriptor, $(kwargs...))
end
macro initialise!(habitatdescriptor, kwargs...)
#FIXME does the habitatdescriptor need to be `esc`aped due to scoping issues?
:($(esc(:initialise!)) = initpopulation($habitatdescriptor, $(kwargs...)))
end
"""
......@@ -145,47 +142,64 @@ variables:
information).
Several utility macros can be used within the body of `@phase` as a short-hand for
common expressions: `@respond`, `@trait`, `@here`, `@kill`, `@reproduce`, `@neighbours`.
common expressions: `@trait`, `@changephase`, `@respond`, `@here`, `@kill`,
`@reproduce`, `@neighbours`.
To transition an individual to another phase, simply redefine its phase variable:
`@trait(phase) = "newphase"`.
Note that the first phase that is defined in a species definition block will be
the phase that animals are assigned at birth, unless the variable `phase` is
explicitly defined by the user in the species definition block.
"""
macro phase(name, body)
#XXX make this documentable?
#FIXME Somehow, errors in the phase body are not shown?
quote
$(esc(name)) = function(animal::Animal, model::AgentBasedModel)
$(esc(:pos)) = animal.pos
$body
$(esc(name)) = function($(esc(:animal))::Animal, $(esc(:model))::AgentBasedModel)
$(esc(:pos)) = $(esc(:animal)).pos
#@debug "Executing phase "*$(String(name))*":\n"*$(esc(body))
$(esc(body)) #FIXME isn't being executed
end
($(esc(:phase)) == "") && ($(esc(:phase)) = $(String(name)))
end
end
"""
@respond(eventname, body)
@trait(traitname)
Define how an animal responds to a landscape event that affects its current position.
A utility macro to quickly access an animal's trait value.
This can only be used nested within `@phase`.
"""
macro respond(eventname, body)
quote
if $(esc(eventname)) in @here(events)
$body
end
macro trait(traitname)
#XXX This would error if called in the first part of a species definition block
# (i.e. outside of a @phase block). Although this is specified in the documentation,
# it is unexpected and liable to be overlooked. Can we add a third clause to
# compensate for that?
if traitname in fieldnames(Animal)
:($(esc(:animal)).$(traitname))
else
:($(esc(:animal)).traits[string($(QuoteNode(traitname)))])
end
end
"""
@trait(traitname)
@changephase(newphase)
A utility macro to quickly access an animal's trait value.
Switch this animal over to a different phase. This can only be used nested within `@phase`.
"""
macro changephase(newphase)
:($(esc(:animal)).traits["phase"] = $(String(newphase)))
end
"""
@respond(eventname, body)
Define how an animal responds to a landscape event that affects its current position.
This can only be used nested within `@phase`.
"""
macro trait(traitname)
if traitname in fieldnames(Animal)
:(animal.$(traitname))
else
:(animal.traits[string($(QuoteNode(traitname)))])
macro respond(eventname, body)
quote
if $(esc(eventname)) in @here(events)
$(esc(body))
end
end
end
......@@ -196,7 +210,7 @@ A utility macro to quickly access a property of the animal's current position.
This can only be used nested within `@phase`.
"""
macro here(property)
:(model.landscape[animal.pos...].$(property))
:($(esc(:model)).landscape[$(esc(:animal)).pos...].$(property))
end
"""
......@@ -206,7 +220,7 @@ Kill this animal. This is a thin wrapper around `kill!()`, and passes on any arg
This can only be used nested within `@phase`.
"""
macro kill(args...)
:(kill!(animal, model, $(args...)))
:(kill!($(esc(:animal)), $(esc(:model)), $(args...)))
end
"""
......@@ -216,7 +230,7 @@ Let this animal reproduce. This is a thin wrapper around `reproduce!()`, and pas
any arguments. This can only be used nested within `@phase`.
"""
macro reproduce(args...)
:(reproduce!(animal, model, $(args...)))
:(reproduce!($(esc(:animal)), $(esc(:model)), $(args...)))
end
"""
......@@ -226,7 +240,7 @@ Return an iterator over all animals in the given radius around this animal, excl
This can only be used nested within `@phase`.
"""
macro neighbours(radius)
:(nearby_animals(animal, model, $radius))
:(nearby_animals($(esc(:animal)), $(esc(:model)), $radius))
end
"""
......@@ -328,3 +342,5 @@ This is a utility wrapper that can only be used nested within `@phase` or `@habi
macro countanimals(speciesname, radius=0)
:(countanimals($(esc(:pos)), $(esc(:model)), $speciesname, $radius))
end
##TODO add movement macros
......@@ -136,8 +136,11 @@ Count the number of animals of the given species in this location (optionally su
function countanimals(pos::Tuple{Int64,Int64}, model::AgentBasedModel,
speciesname::String, radius::Int64=0)
n = 0
#XXX can we ignore capitalisation in the spelling of `speciesname`?
for a in nearby_animals(pos, model, radius)
a.traits["name"] == speciesname && (n += 1)
end
return n
end
##TODO add movement functions
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment