Thanks. OK, here goes …
The versions are:
Agents v5.6.3
GLMakie v0.6.13
InteractiveDynamics v0.21.11
The code is:
module Basics
using Agents, LinearAlgebra, Random, GLMakie, InteractiveDynamics
@agent Boid ContinuousAgent{2} begin
speed::Float64
cohere_factor::Float64
separation::Float64
separate_factor::Float64
match_factor::Float64
visual_distance::Float64
end
function initialize_model(;
n_boids = 100,
speed = 1.0,
cohere_factor = 0.25,
separation = 4.0,
separate_factor = 0.25,
match_factor = 0.01,
visual_distance = 5.0,
extent = (100, 100),
)
space2d = ContinuousSpace(extent; spacing = visual_distance/1.5)
model = ABM(Boid, space2d, scheduler = Schedulers.Randomly())
for _ in 1:n_boids
vel = Tuple(rand(model.rng, 2) * 2 .- 1)
add_agent!(
model,
vel,
speed,
cohere_factor,
separation,
separate_factor,
match_factor,
visual_distance,
)
end
return model
end
function agent_step!(boid, model)
# Obtain the ids of neighbors within the bird's visual distance
neighbor_ids = nearby_ids(boid, model, model.visual_distance)
N = 0
match = separate = cohere = (0.0, 0.0)
# Calculate behaviour properties based on neighbors
for id in neighbor_ids
N += 1
neighbor = model[id].pos
heading = neighbor .- boid.pos
# `cohere` computes the average position of neighboring birds
cohere = cohere .+ heading
if edistance(boid.pos, neighbor, model) < model.separation
# `separate` repels the bird away from neighboring birds
separate = separate .- heading
end
# `match` computes the average trajectory of neighboring birds
match = match .+ model[id].vel
end
N = max(N, 1)
# Normalise results based on model input and neighbor count
cohere = cohere ./ N .* model.cohere_factor
separate = separate ./ N .* model.separate_factor
match = match ./ N .* model.match_factor
# Compute velocity based on rules defined above
boid.vel = (boid.vel .+ cohere .+ separate .+ match) ./ 2
boid.vel = boid.vel ./ norm(boid.vel)
# Move bird according to new velocity and speed
move_agent!(boid, model, boid.speed)
end
const boid_polygon = Polygon(Point2f[(-0.5, -0.5), (1, 0), (-0.5, 0.5)])
function boid_marker(b::Boid)
φ = atan(b.vel[2], b.vel[1]) #+ π/2 + π
scale(rotate2D(boid_polygon, φ), 2)
end
## Plotting the flock
function demo()
model = initialize_model()
# figure, = abmplot(model; am = boid_marker)
# figure
abmvideo(
"flocking.mp4", model, agent_step!;
am = boid_marker,
framerate = 20, frames = 100,
title = "Flocking"
)
end
end
The stack trace is:
ERROR: type Nothing has no field visual_distance
Stacktrace:
[1] getproperty
@ .\Base.jl:38 [inlined]
[2] getproperty(m::Agents.AgentBasedModel{Agents.ContinuousSpace{2, true, Float64, typeof(Agents.no_vel_update)}, Main.Basics.Boid, Agents.Schedulers.Randomly, Nothing, Random.TaskLocalRNG}, s::Symbol)
@ Agents C:\Users\hswt136nia\.julia\packages\Agents\9UdZV\src\core\model.jl:165
[3] agent_step!(boid::Main.Basics.Boid, model::Agents.AgentBasedModel{Agents.ContinuousSpace{2, true, Float64, typeof(Agents.no_vel_update)}, Main.Basics.Boid, Agents.Schedulers.Randomly, Nothing, Random.TaskLocalRNG})
@ Main.Basics C:\Users\hswt136nia\OneDrive\Documents\Rock Dene Cottage\Playing\Julia\Sandpit\Basics.jl:44
[4] step!(model::Agents.AgentBasedModel{Agents.ContinuousSpace{2, true, Float64, typeof(Agents.no_vel_update)}, Main.Basics.Boid, Agents.Schedulers.Randomly, Nothing, Random.TaskLocalRNG}, agent_step!::typeof(Main.Basics.agent_step!), model_step!::typeof(Agents.dummystep), n::Int64, agents_first::Bool)
@ Agents C:\Users\hswt136nia\.julia\packages\Agents\9UdZV\src\simulations\step.jl:55
[5] step!
@ C:\Users\hswt136nia\.julia\packages\Agents\9UdZV\src\simulations\step.jl:48 [inlined]
[6] step!(abmobs::InteractiveDynamics.ABMObservable{Agents.AgentBasedModel{Agents.ContinuousSpace{2, true, Float64, typeof(Agents.no_vel_update)}, Main.Basics.Boid, Agents.Schedulers.Randomly, Nothing, Random.TaskLocalRNG}, typeof(Main.Basics.agent_step!), typeof(Agents.dummystep), Nothing, Nothing, Nothing, Nothing, Bool}, n::Int64; kwargs::Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}})
@ InteractiveDynamics C:\Users\hswt136nia\.julia\packages\InteractiveDynamics\EThtU\src\agents\model_observable.jl:53
[7] step!
@ C:\Users\hswt136nia\.julia\packages\InteractiveDynamics\EThtU\src\agents\model_observable.jl:51 [inlined]
[8] (::InteractiveDynamics.var"#93#96"{Int64, Int64, InteractiveDynamics.ABMObservable{Agents.AgentBasedModel{Agents.ContinuousSpace{2, true, Float64, typeof(Agents.no_vel_update)}, Main.Basics.Boid, Agents.Schedulers.Randomly, Nothing, Random.TaskLocalRNG}, typeof(Main.Basics.agent_step!), typeof(Agents.dummystep), Nothing, Nothing, Nothing, Nothing, Bool}, Observables.Observable{Int64}})(io::Makie.VideoStream)
@ InteractiveDynamics C:\Users\hswt136nia\.julia\packages\InteractiveDynamics\EThtU\src\agents\convenience.jl:152
[9] Record(func::InteractiveDynamics.var"#93#96"{Int64, Int64, InteractiveDynamics.ABMObservable{Agents.AgentBasedModel{Agents.ContinuousSpace{2, true, Float64, typeof(Agents.no_vel_update)}, Main.Basics.Boid, Agents.Schedulers.Randomly, Nothing, Random.TaskLocalRNG}, typeof(Main.Basics.agent_step!), typeof(Agents.dummystep), Nothing, Nothing, Nothing, Nothing, Bool}, Observables.Observable{Int64}}, figlike::Makie.Figure; framerate::Int64)
@ Makie C:\Users\hswt136nia\.julia\packages\Makie\Ppzqh\src\display.jl:583
[10] #record#957
@ C:\Users\hswt136nia\.julia\packages\Makie\Ppzqh\src\display.jl:577 [inlined]
[11] abmvideo(file::String, model::Agents.AgentBasedModel{Agents.ContinuousSpace{2, true, Float64, typeof(Agents.no_vel_update)}, Main.Basics.Boid, Agents.Schedulers.Randomly, Nothing, Random.TaskLocalRNG}, agent_step!::typeof(Main.Basics.agent_step!), model_step!::typeof(Agents.dummystep); spf::Int64, framerate::Int64, frames::Int64, title::String, showstep::Bool, figure::NamedTuple{(:resolution,), Tuple{Tuple{Int64, Int64}}}, axis::NamedTuple{(), Tuple{}}, recordkwargs::NamedTuple{(:compression,), Tuple{Int64}}, kwargs::Base.Pairs{Symbol, typeof(Main.Basics.boid_marker), Tuple{Symbol}, NamedTuple{(:am,), Tuple{typeof(Main.Basics.boid_marker)}}})
@ InteractiveDynamics C:\Users\hswt136nia\.julia\packages\InteractiveDynamics\EThtU\src\agents\convenience.jl:149
[12] demo()
@ Main.Basics C:\Users\hswt136nia\OneDrive\Documents\Rock Dene Cottage\Playing\Julia\Sandpit\Basics.jl:85
[13] top-level scope
@ REPL[3]:1