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

Changed model RNG to StableRNG and enforced its use

parent 60ff8280
Branches
Tags
No related merge requests found
......@@ -6,6 +6,6 @@ then
rm -r temp_results
fi
./run.jl -o temp_results -s 2
./run.jl -o temp_results
src/analysis/analyse_nature.R temp_results
......@@ -21,6 +21,7 @@ using
LoggingExtras,
#MacroTools, #http://fluxml.ai/MacroTools.jl/stable/utilities/
Random,
StableRNGs,
TOML
## define exported functions and variables
......@@ -56,7 +57,7 @@ export
initialise,
stepsimulation!,
createevent!,
finalise
finalise!
## include all module files (note that the order matters - if file
## b references something from file a, it must be included later)
......
......@@ -33,7 +33,7 @@ Precedence: commandline parameters - user config file - default values
function getsettings(configfile::String, seed::Union{Int64,Nothing}=nothing)
# read in and merge configurations from the commandline, the default config file
# and a user-supplied config file
defaults = TOML.parsefile(configfile)
defaults::Dict{String, Dict{String, Any}} = TOML.parsefile(configfile)
commandline = parsecommandline()
if haskey(commandline, "configfile") && isfile(commandline["configfile"])
configs = TOML.parsefile(commandline["configfile"])
......
......@@ -42,7 +42,7 @@ function setupdatadir(model::AgentBasedModel)
simulationlogger = TeeLogger(ConsoleLogger(logfile, loglevel),
ConsoleLogger(stdout, loglevel))
global_logger(simulationlogger)
@debug "Setting up output directory $(@param(core.outdir))"
@debug "Setting up output directory $(@param(core.outdir))."
# Export a copy of the current parameter settings to the output folder.
# This can be used to replicate this exact run in future, and also
# records the current time and git commit.
......
......@@ -20,7 +20,6 @@ configuration file and overriding the `seed` parameter.
function initialise(config::String=PARAMFILE, seed::Union{Int64,Nothing}=nothing)
@info "Simulation run started at $(Dates.now())."
settings = getsettings(config, seed)
Random.seed!(settings["core"]["seed"])
events = Vector{FarmEvent}()
dataoutputs = Vector{DataOutput}()
landscape = initlandscape(settings["core"]["landcovermap"], settings["core"]["farmfieldsmap"])
......@@ -32,7 +31,7 @@ function initialise(config::String=PARAMFILE, seed::Union{Int64,Nothing}=nothing
:events=>events)
@debug "Setting up model."
model = AgentBasedModel(Union{Farmer,Animal,FarmPlot}, space, properties=properties,
rng=Random.Xoshiro(settings["core"]["seed"]), warn=false)
rng=StableRNG(settings["core"]["seed"]), warn=false)
setupdatadir(model)
initfarms!(model)
initfields!(model)
......@@ -61,15 +60,15 @@ function stepsimulation!(model::AgentBasedModel)
end
"""
finalise(model)
finalise!(model)
Wrap up the simulation. Currently doesn't do anything except print some information.
"""
function finalise(model::AgentBasedModel)
function finalise!(model::AgentBasedModel)
@info "Simulated $(model.date-@param(core.startdate))."
@info "Simulation run completed at $(Dates.now()),\nwrote output to $(@param(core.outdir))."
#XXX is there anything to do here?
#genocide!(model)
model
end
"""
......@@ -82,5 +81,5 @@ function simulate(config::String=PARAMFILE, seed::Union{Int64,Nothing}=nothing)
model = initialise(config, seed)
runtime = Dates.value(@param(core.enddate)-@param(core.startdate))+1
step!(model, dummystep, stepsimulation!, runtime)
finalise(model)
finalise!(model)
end
......@@ -21,9 +21,10 @@ end
"""
savepopulationdata(model)
Print a comma-separated set of lines to `populations.csv`, giving the current date
and population size for each animal species. May be called never, daily, monthly,
yearly, or at the end of a simulation, depending on the parameter `nature.popoutfreq`.
Return a comma-separated set of lines (to be printed to `populations.csv`), giving
the current date and population size for each animal species. May be called never,
daily, monthly, yearly, or at the end of a simulation, depending on the parameter
`nature.popoutfreq`.
"""
function savepopulationdata(model::AgentBasedModel)
pops = Dict{String,Int}(s=>0 for s = @param(nature.targetspecies))
......@@ -41,10 +42,10 @@ end
"""
saveindividualdata(model)
Print a comma-separated set of lines to `individuals.csv`, listing all properties
of all animal individuals in the model. May be called never, daily, monthly, yearly, or
at the end of a simulation, depending on the parameter `nature.indoutfreq`.
WARNING: Produces very big files!
Return a comma-separated set of lines (to be printed to `individuals.csv`), listing
all properties of all animal individuals in the model. May be called never, daily,
monthly, yearly, or at the end of a simulation, depending on the parameter
`nature.indoutfreq`. WARNING: Produces very big files!
"""
function saveindividualdata(model::AgentBasedModel)
data = ""
......
......@@ -156,7 +156,7 @@ variables:
Several utility macros can be used within the body of `@phase` as a short-hand for
common expressions: `@trait`, `@setphase`, `@respond`, `@here`, `@kill`,
`@reproduce`, `@neighbours`.
`@reproduce`, `@neighbours`, `@rand`.
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
......@@ -197,6 +197,7 @@ end
Switch this animal over to a different phase. This can only be used nested within `@phase`.
"""
macro setphase(newphase)
#XXX make this usable in the top part of a species definition?
:($(esc(:animal)).traits["phase"] = $(String(newphase)))
end
......@@ -364,4 +365,14 @@ macro countanimals(args...)
:(countanimals($(esc(:pos)), $(esc(:model)); $(map(esc, args)...)))
end
"""
@rand(args...)
Return a random number or element from the sample, using the model RNG.
This is a utility wrapper that can only be used nested within `@phase` or `@habitat`.
"""
macro rand(args...)
:(rand($(esc(:model)).rng, $(map(esc, args)...)))
end
##TODO add movement macros
......@@ -40,15 +40,15 @@ function initpopulation(habitatdescriptor::Function; phase::Union{String,Nothing
(!isnothing(phase)) && (species["phase"] = phase)
width, height = size(model.landscape)
while n == 0 || n < popsize
for x in shuffle!(Vector(1:width))
for y in shuffle!(Vector(1:height))
for x in shuffle!(model.rng, Vector(1:width))
for y in shuffle!(model.rng, Vector(1:height))
if habitatdescriptor((x,y), model)
if pairs
add_agent!((x,y), Animal, model, deepcopy(species), female, 0)
add_agent!((x,y), Animal, model, deepcopy(species), male, 0)
n += 2
else
sex = asexual ? hermaphrodite : rand([male, female])
sex = asexual ? hermaphrodite : rand(model.rng, [male, female])
add_agent!((x,y), Animal, model, deepcopy(species), sex, 0)
n += 1
end
......@@ -88,7 +88,7 @@ Produce one or more offspring for the given animal at its current location.
"""
function reproduce!(animal::Animal, model::AgentBasedModel, n::Int64=1)
for i in 1:n
sex = (animal.sex == hermaphrodite) ? hermaphrodite : rand([male, female])
sex = (animal.sex == hermaphrodite) ? hermaphrodite : rand(model.rng, [male, female])
# We need to generate a fresh species dict here
species = @eval $(Symbol(animal.traits["name"]))($model)
add_agent!(animal.pos, Animal, model, species, sex, 0)
......@@ -103,7 +103,7 @@ Kill this animal, optionally with a given percentage probability.
Returns true if the animal dies, false if not.
"""
function kill!(animal::Animal, model::AgentBasedModel, probability::Float64=1.0, cause::String="")
if rand() < probability
if rand(model.rng) < probability
postfix = isempty(cause) ? "." : " from $cause."
@debug "$(animalid(animal)) has died$(postfix)"
kill_agent!(animal, model)
......
......@@ -25,11 +25,12 @@ of a deer.
"""
@phase lifephase begin
direction = Tuple(rand([-1,1], 2))
for i in 1:rand(1:@trait(maxspeed))
for i in 1:@rand(1:@trait(maxspeed))
walk!(animal, direction, model; ifempty=false)
end
if rand() < @trait(fecundity) && @countanimals(species="Wolpertinger") < @trait(crowding)
if @rand() < @trait(fecundity) &&
@countanimals(species="Wolpertinger") < @trait(crowding)
@reproduce
end
......
......@@ -30,15 +30,15 @@ legs, but that doesn't make it any less dangerous...
# check if a wolpertinger is in pouncing distance
if a.traits["name"] == "Wolpertinger"
move_agent!(animal, a.pos, model)
if rand() < @trait(huntsuccess)
if @rand() < @trait(huntsuccess)
@debug "$(animalid(animal)) killed $(animalid(a))."
kill_agent!(a, model)
@goto reproduce
end
elseif a.traits["name"] == "Wyvern" && rand() < @trait(aggression)
elseif a.traits["name"] == "Wyvern" && @rand() < @trait(aggression)
# wyverns also fight against each other if they get too close
move_agent!(animal, a.pos, model)
outcome = rand()
outcome = @rand()
if outcome < 0.4
@debug "$(animalid(animal)) killed $(animalid(a)) in a fight."
kill_agent!(a, model)
......@@ -49,7 +49,7 @@ legs, but that doesn't make it any less dangerous...
end
end
# check if a wolpertinger is in seeing distance, or walk in a random direction
direction = Tuple(rand([-1,1], 2))
direction = Tuple(@rand([-1,1], 2))
for a in @neighbours(@trait(vision))
if a.traits["name"] == "Wolpertinger"
direction = get_direction(animal.pos, a.pos, model)
......@@ -61,7 +61,7 @@ legs, but that doesn't make it any less dangerous...
end
# reproduce every once in a blue moon
@label reproduce
(rand() < @trait(fecundity)) && @reproduce
(@rand() < @trait(fecundity)) && @reproduce
# hibernate from November to March
if monthday(model.date) == (11,1)
@trait(phase) = "winter"
......
......@@ -13,10 +13,10 @@ farmfieldsmap = "data/fields_jena.tif" # location of the field geometry map
outdir = "results" # location and name of the output folder
overwrite = "ask" # overwrite the output directory? (true/false/"ask")
loglevel = "debug" # verbosity level: "debug", "info", "quiet"
seed = 0 # seed value for the RNG (0 -> random value)
seed = 2 # seed value for the RNG (0 -> random value)
# dates to start and end the simulation
startdate = 2022-01-01
#enddate = 2022-01-02
#enddate = 2022-03-31
enddate = 2022-12-31
[farm]
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment