Difficulties with the step function

Here I have a 6 X 3 array of agents. Each line has agents with the same age: the first line with age 20 and the last with age 25.

I think I have no problems with the initialize function. But when I try to advance a step I start to have multiple problems, so I think I am doing something really wrong.

I put comments in the code but what I want is: in each step I want to kill that last line (agents with 25 years) and the agents with age >= age.death (is own age.death which is known).

Last, I want create a new first row of agents with 20 years and put them in the first row.

using Agents
using Random
import DrWatson: @dict

mutable struct Person <: AbstractAgent
    id::Int
    pos::NTuple{2, Int}
    age::Int
    death_age::Int
end

function initialize(; numagents = 18, seed = 125,
    max_age = 25, min_age = 20, 
    griddims = ((max_age - min_age) + 1, Int(numagents/((max_age - min_age) + 1))))
    space = GridSpace(griddims, periodic = false)
    rng = Random.MersenneTwister(seed)
    properties = @dict max_age min_age griddims
    model = ABM(
        Person, space; properties,
        rng, scheduler = Schedulers.randomly
    )
    
    grid = collect(positions(model))
    num_positions = prod(griddims)
    #println(grid)

    age = collect(repeat(min_age:max_age, griddims[2]))

    i = 1
    for p in grid
        agent = Person(
            i,
            p,
            age[i],
            rand(model.rng, 24:25)
            )
        add_agent!(agent, model)
        println(agent.id, " p ", p, " age ", age[i], " death ", agent.death_age)
        i += 1
    end

    return model
end


function agent_step!(agent, model)
    # Delete the last line of agents
    if agent.age == model.max_age
        kill_agent!(agent, model)
    end
    agent.age += 1 # each agent becomes older one year

    # kill all agent that are older than their death.age
    if agent.age >= agent.death_age
        kill_agent!(agent, model)
    end

    agent.pos = (agent.pos[1] + 1, agent.pos[2]) # move each agent down one position

    # create model.griddims[2] new agents with age model.min_age and position them in the first row (1,k)
    for k in 1:model.griddims[2]
        agent = Person(
            nextid(model),
            (1, k),
            model.min_age,
            rand(model.rng, 24:25)
            )
        add_agent!(agent, model)
    end

    return
end

model = initialize()


#step!(model, agent_step!)

adata = [:pos, :age, :death_age]

adf, _ = run!(model, agent_step!, dummystep, 3; adata)

That’s not how you move agents in Agents.jl. You use the move_agent! function. Agent location is stored both in the agent pos field but also in teh spatial structure to accelerate searches. Changing the position arbitrarily like that instead of using the API would lead to all sorts of nonsensical things happen, which I think is what you see here?

Also, better to use size(model.space) rather than model.griddims

1 Like

Thanks. I already tried move_agent! without sucess. But I will try it again.

No hope with these changes of the agent_step! function.

function agent_step!(agent, model)
    # Delete the last line of agents
    if agent.age == model.max_age
        kill_agent!(agent, model)
    end
    agent.age += 1 # each agent becomes older one year

    kill all agent that are older than their death.age
    if agent.age >= agent.death_age
        kill_agent!(agent, model)
    end

    new_pos = (agent.pos[1] + 1, agent.pos[2])
    move_agent!(agent, new_pos, model) # move each agent down one position

    # create size(model.space)[2] new agents with age model.min_age and position them in the first row (1,k)
    for k in 1:size(model.space)[2]
        agent = Person(
            nextid(model),
            (1, k),
            model.min_age,
            rand(model.rng, 24:25)
            )
        add_agent!(agent, model)
    end

    return
end

please read the documentation string of add_agent!. If you don’t specify a position, the agent is added to a random position. You want to use the function add_agent_pos! instead.

Thank you, George. I think I have managed everything now. I have used another possibility for add_agent! that I’ve read in the documentation: add_agent!(agent, pos, model). But I also have tried add_agent_pos! as well.

This is my complete solution (I have some difficulty to understand why I have to use restrictions like if agent.pos[1] < 6 or if isempty((1,1), model), but I am sure there are other cleaner solutions for this problem):

using Agents
using Random
import DrWatson: @dict

mutable struct Person <: AbstractAgent
    id::Int
    pos::NTuple{2, Int}
    age::Int
    death_age::Int
end

function initialize(; numagents = 18, seed = 125,
    max_age = 25, min_age = 20, 
    griddims = ((max_age - min_age) + 1, Int(numagents/((max_age - min_age) + 1))))
    space = GridSpace(griddims, periodic = false)
    rng = Random.MersenneTwister(seed)
    properties = @dict max_age min_age
    model = ABM(
        Person, space; properties,
        rng, scheduler = Schedulers.randomly
    )
    
    grid = collect(positions(model))

    age = collect(repeat(min_age:max_age, size(model.space)[2]))

    for (i, pos) in enumerate(grid)
        agent = Person(
            i,
            pos,
            age[i],
            rand(model.rng, 24:25)
            )
        add_agent!(agent, pos, model)
    end

    return model
end

function agent_step!(agent, model)
    # Delete the last line of agents
    # kill all agent that are older than their death.age
    if agent.age == model.max_age | agent.age >= agent.death_age
        kill_agent!(agent, model)
    end
    agent.age += 1 # each agent becomes older one year

    # move each agent down one position
    if agent.pos[1] < 6
        new_pos = (agent.pos[1] + 1, agent.pos[2])
        move_agent!(agent, new_pos, model)
    end
    
    # create size(model.space)[2] new agents with age model.min_age
    # and position them in the first row (1,k)
    if isempty((1,1), model)
        for k in 1:size(model.space)[2]
            agent = Person(
                nextid(model),
                (1, k),
                model.min_age,
                rand(model.rng, 24:25)
                )
            add_agent!(agent, (1,k), model)
        end
    end
end