diff --git a/src/core/simulation.jl b/src/core/simulation.jl index b805fb1e67bb1d75450b9a5f243ff05bbea301ac..05a90d9e389b0687881331257e906209cef499f0 100644 --- a/src/core/simulation.jl +++ b/src/core/simulation.jl @@ -48,14 +48,12 @@ Execute one update of the model. function stepsimulation!(model::AgentBasedModel) @info "Simulating day $(model.date)." for a in Schedulers.ByType((Farmer,FarmPlot,Animal), true)(model) - #The animal may have been killed, so we need a try/catch - # try - # stepagent!(model[a], model) - # catch exc - # #FIXME check if the KeyError comes from the model[a] or the function call - # isa(exc, KeyError) ? continue : throw(exc) - # end - stepagent!(model[a], model) + try #The animal may have been killed + stepagent!(model[a], model) + catch exc + # check if the KeyError comes from the `model[a]` or the function call + isa(exc, KeyError) && isa(exc.key, Int) ? continue : throw(exc) + end end updateevents!(model) outputdata(model) diff --git a/src/nature/nature.jl b/src/nature/nature.jl index c8696da3353a02c6595b38e5f7b83e5a9141bde6..3606cd1edc5d6ebd469a3e8c41366cebc5bf2100 100644 --- a/src/nature/nature.jl +++ b/src/nature/nature.jl @@ -62,6 +62,11 @@ end ### MACROS IMPLEMENTING THE DOMAIN-SPECIFIC LANGUAGE FOR DEFINING SPECIES +## Note that this DSL consists of lots of deeply nested macro calls, which is a +## known tricky issue in Julia (https://github.com/JuliaLang/julia/issues/23221, +## https://github.com/p-i-/MetaGuideJulia/wiki#example-swap-macro-to-illustrate-esc). +## Hence all the `esc`apes in the following code - be careful when modifying! + """ @species(name, body) @@ -125,8 +130,7 @@ Note: if this macro is not used, the variable `initialise!` must be set manually species definition. """ macro initialise(habitatdescriptor, kwargs...) - #FIXME does the habitatdescriptor need to be `esc`aped due to scoping issues? - :($(esc(:initialise!)) = initpopulation($habitatdescriptor, $(kwargs...))) + :($(esc(:initialise!)) = initpopulation($(esc(habitatdescriptor)); $(map(esc, kwargs)...))) end """ @@ -159,6 +163,7 @@ 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) + #TODO the docstrings give a lot of warnings in the log - can I fix that? quote Core.@__doc__ function $(esc(name))($(esc(:animal))::Animal, $(esc(:model))::AgentBasedModel) $(esc(:pos)) = $(esc(:animal)).pos @@ -251,7 +256,7 @@ This can only be used nested within `@phase`. """ macro neighbours(radius) #TODO enable filtering by species - :(nearby_animals($(esc(:animal)), $(esc(:model)), $radius)) + :(nearby_animals($(esc(:animal)), $(esc(:model)), $(esc(radius)))) end """ @@ -336,7 +341,7 @@ Calculate the distance to the closest habitat of the specified type or descripto This is a utility wrapper that can only be used nested within `@phase` or `@habitat`. """ macro distanceto(habitat) - :(distanceto($(esc(:pos)), $(esc(:model)), $habitat)) + :(distanceto($(esc(:pos)), $(esc(:model)), $(esc(habitat)))) end """ diff --git a/src/nature/species/wyvern.jl b/src/nature/species/wyvern.jl index c852d69f800f2120c50038909a53ea30195b798b..dc6be0b625f49784a395ba875f6fe0243d59488d 100644 --- a/src/nature/species/wyvern.jl +++ b/src/nature/species/wyvern.jl @@ -18,7 +18,7 @@ legs, but that doesn't make it any less dangerous... aggression = 0.2 huntsuccess = 0.8 - initialise! = initrandompopulation(popsize) + @initialise(@habitat(@landcover() in (grass, soil, agriculture, builtup)), popsize=popsize) phase = "winter" """ @@ -26,7 +26,7 @@ legs, but that doesn't make it any less dangerous... prey: wolpertingers... """ @phase summer begin - for a in nearby_agents(animal, model, @trait(speed)) + for a in @neighbours(@trait(speed)) # check if a wolpertinger is in pouncing distance if a.traits["name"] == "Wolpertinger" move_agent!(animal, a.pos, model) @@ -50,7 +50,7 @@ legs, but that doesn't make it any less dangerous... end # check if a wolpertinger is in seeing distance, or walk in a random direction direction = Tuple(rand([-1,1], 2)) - for a in nearby_agents(animal, model, @trait(vision)) + for a in @neighbours(@trait(vision)) if a.traits["name"] == "Wolpertinger" direction = get_direction(animal.pos, a.pos, model) break diff --git a/src/parameters.toml b/src/parameters.toml index 8495d50167c1eb90922ae5dcf18edb2eac8a424c..d0281848d3e4ef0f142e8ca34a597531937adfe0 100644 --- a/src/parameters.toml +++ b/src/parameters.toml @@ -16,8 +16,8 @@ loglevel = "debug" # verbosity level: "debug", "info", "quiet" seed = 0 # 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-12-31 +#enddate = 2022-01-02 +enddate = 2022-12-31 [farm] farmmodel = "FieldManager" # which version of the farm model to use (not yet implemented) diff --git a/test/nature_tests.jl b/test/nature_tests.jl index e44fbc08780212c83c58f1c978d88eccfce17084..b8d4937bee3af19dbf633bb0c5645b8b1934d82d 100644 --- a/test/nature_tests.jl +++ b/test/nature_tests.jl @@ -15,7 +15,7 @@ h1 = @habitat(@landcover() == Ps.water) h2 = @habitat(@croptype() == Ps.wheat && @cropheight() < 2) - h3 = @habitat(@distanceto(water) > 2 && + h3 = @habitat(@distanceto(Ps.water) > 2 && @distancetoedge() <= 2) h4 = @habitat(@countanimals(species="test_animal", radius=1) == 1) # test the descriptors @@ -67,18 +67,13 @@ end end @testset "Species macros" begin - #FIXME I am having tons of trouble here with module scoping and macro expansion, - # a known tricky issue in Julia (https://github.com/JuliaLang/julia/issues/23221, - # https://github.com/p-i-/MetaGuideJulia/wiki#example-swap-macro-to-illustrate-esc). - # Basically, one needs to avoid nesting modules too deeply (i.e. more than one nesting level) - # -- is that so?? -- + # create a model landscape and a test species model = smalltestlandscape(Union{Animal,Farmer,FarmPlot}) @species Mermaid begin ageofmaturity = 2 pesticidemortality = 1.0 - #@initialise!(@habitat(@landcover() == Persephone.water), pairs=true) #FIXME - initialise! = Persephone.initpopulation(@habitat(@landcover() == Persephone.water), pairs=true) + @initialise(@habitat(@landcover() == Persephone.water), pairs=true) @phase life begin @debug "$(Persephone.animalid(animal)) is swimming happily in its pond." @respond Persephone.pesticide @kill(@trait(pesticidemortality))