Can't I update velocity AND position of a continuous agent using a custom move_agent! that is not based on forward euler?

I am using the latest Agents.jl (v.6.2.4) package and learning it as well. I want to implement a simple movement of different agents by trying out various differential equation solvers (besides the default forward euler provided by move_agent!, as mentioned in the docs)
I read in the docs, that for continuous agents in continuous space with periodic boundaries, move_agent! is used for agent_step! function, but for a more complex agent_step!, one can also update the velocities in agent_step!.

However, I have noticed, that I can maybe only update velocities, because explicitly updating positions can lead to errors that an agent is beyond the defined extent. (is that true?)

this is my code:

using Agents, Random
using CairoMakie

Random.seed!(42)
@agent struct Pedestrian(ContinuousAgent{2,Float64})
    desired_velocity::Vector{Float64}  # Custom property
end

function agent_step!(agent::Pedestrian, model,dt = 0.1)
    # agent.pos = agent.pos + dt*agent.desired_velocity # may lead to out of extent errors
    agent.vel = agent.vel + dt*agent.desired_velocity
    move_agent!(agent,model,dt)
end

# Add agents with random initial positions/velocities
function initialize(number_of_peds = 4, x_len = 10, y_len = 10)
    spacing = 1/20
    space = ContinuousSpace((x_len, y_len); spacing)
    model = StandardABM(
        Pedestrian,
        space;
        agent_step!,
        scheduler = Schedulers.Randomly()
    )
    for i in 1:number_of_peds
        add_agent!(model;
            pos = rand(2).*10,  # Initial position
            vel = [0,0], # Initial velocity
            desired_velocity = (i-1 < (number_of_peds ÷ 2) ? [1,0] : [-1,0])
        )
    end
    return model
end


model = initialize()

for i in 1:10
    step!(model)
    plot, = abmplot(model)
    display(plot)
    sleep(0.1)
end

What i wish to implement is something similar to a Leapfrog_integration where one can update both positions and velocities at each time step.
Since I am new to Julia, I understand i might be making some mistakes in the code as well.
Any suggestion/advice would be greatly appreciated, Thank you! :slight_smile:

You can use normalize_position to wrap any evaluated position within your model boundaries, e.g. in the line you commented out in your agent_step! function you could write instead

newpos = normalize_position(agent.pos + dt*agent.desired_velocity, model)
move_agent!(agent, newpos, model)

So you can just use whatever integrator you want, just call normalize_position before trying to update the agent position.

Alternatively, you can use the walk! function instead which respects the model boundary conditions without the need for you to do it explicitly.

2 Likes