# Calculating displacement vectors between Agents

**URL:** <https://discourse.julialang.org/t/calculating-displacement-vectors-between-agents/95458>\
**Category:** Modelling & Simulations\
**Tags:** question\
**Created:** [March 2, 2023, 5:34pm UTC](https://discourse.julialang.org/t/calculating-displacement-vectors-between-agents/95458 "2023-03-02T17:34:34Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![Niall](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/niall/32/22517_2.png) [@Niall](https://discourse.julialang.org/u/Niall)\
**Post date:** [March 2, 2023, 5:34pm UTC](https://discourse.julialang.org/t/calculating-displacement-vectors-between-agents/95458/1 "2023-03-02T17:34:34Z")

</div>

Hi. I’m having problems (re-)implementing the Flocking model in Agents. Whenever I run it, flocks tend to bounce off the supposedly periodic boundaries, and when I analyse this more closely, the individual agents ‘stick’ to the boundary. This appears to be due to the following code in the method `agent_step!()`:

`heading = neighbor .- bird.pos`

The problem is that this heading vector takes no account of neighbours that are just over the periodic boundary. See for example the following code:

```julia
julia> using Agents
julia> model = ABM(ContinuousAgent{2},ContinuousSpace((5,5)))
AgentBasedModel with 0 agents of type ContinuousAgent
 space: periodic continuous space with (5.0, 5.0) extent and spacing=0.25
 scheduler: fastest
julia> add_agent!((0.1,3.0),model,(1.0,1.0))
ContinuousAgent{2}(1, (0.1, 3.0), (1.0, 1.0))
julia> add_agent!((4.9,3.0),model,(1.0,1.0))
ContinuousAgent{2}(2, (4.9, 3.0), (1.0, 1.0))

julia> nearest_neighbor(model[1],model,1.0)
ContinuousAgent{2}(2, (4.9, 3.0), (1.0, 1.0))

julia> euclidean_distance(model[1],model[2],model)
0.1999999999999993

julia> model[2].pos .- model[1].pos
(4.800000000000001, 0.0)

```

So my question is this: Is there a method for calculating the displacement vector between two positions in a space, which respects the periodic boundary conditions? In the case of the above code, this would hopefully yield something like:

```julia
julia> displacement( model[2].pos, model[1].pos)
(0.2, 0.0)

```

---

<div class="post-metadata">

**Author:** ![Niall](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/niall/32/22517_2.png) [@Niall](https://discourse.julialang.org/u/Niall)\
**Post date:** [March 3, 2023, 9:34am UTC](https://discourse.julialang.org/t/calculating-displacement-vectors-between-agents/95458/2 "2023-03-03T09:34:25Z")

</div>

OK, found it for myself: `get_direction()` Have replaced the relevant line in Flocking by:

```julia
heading = get_direction( bird.pos, neighbor)

```

and it now works fine with no ‘sticking’ at the boundaries.

---

<div class="post-metadata">

**Author:** ![Freya\_the\_Goddess](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/freya_the_goddess/32/36835_2.png) [@Freya\_the\_Goddess](https://discourse.julialang.org/u/Freya_the_Goddess)\
**Post date:** [March 3, 2023, 2:02pm UTC](https://discourse.julialang.org/t/calculating-displacement-vectors-between-agents/95458/3 "2023-03-03T14:02:52Z")

</div>

I am trying to edit the code with yours, but it fails:

```julia
using Agents
using Random, LinearAlgebra

@agent Bird ContinuousAgent{2} begin
    speed::Float64
    cohere_factor::Float64
    separation::Float64
    separate_factor::Float64
    match_factor::Float64
    visual_distance::Float64
end

function initialize_model(;
    n_birds = 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),
    seed = 42,
)
    space2d = ContinuousSpace(extent; spacing = visual_distance/1.5)
    rng = Random.MersenneTwister(seed)

    model = ABM(ContinuousAgent{2},ContinuousSpace((5,5)))
    for _ in 1:n_birds
        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

model = initialize_model()

# Defining the agent_step

function agent_step!(bird, model)
    # Obtain the ids of neighbors within the bird's visual distance
    neighbor_ids = nearby_ids(bird, model, bird.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 = get_direction( bird.pos, neighbor)

        # `cohere` computes the average position of neighboring birds
        cohere = cohere .+ heading
        if euclidean_distance(bird.pos, neighbor, model) < bird.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 .* bird.cohere_factor
    separate = separate ./ N .* bird.separate_factor
    match = match ./ N .* bird.match_factor
    # Compute velocity based on rules defined above
    bird.vel = (bird.vel .+ cohere .+ separate .+ match) ./ 2
    bird.vel = bird.vel ./ norm(bird.vel)
    # Move bird according to new velocity and speed
    move_agent!(bird, model, bird.speed)
end

# Plotting the flock
using InteractiveDynamics
using CairoMakie

const bird_polygon = Polygon(Point2f[(-0.5, -0.5), (1, 0), (-0.5, 0.5)])
function bird_marker(b::Bird)
    φ = atan(b.vel[2], b.vel[1]) #+ π/2 + π
    scale(rotate2D(bird_polygon, φ), 2)
end

# add_agent!((0.1,3.0),model,(1.0,1.0))
# add_agent!((4.9,3.0),model,(1.0,1.0))
# nearest_neighbor(model[1],model,1.0)
# euclidean_distance(model[1],model[2],model)
# model[2].pos .- model[1].pos

model = initialize_model()
figure, = abmplot(model; am = bird_marker)
figure

abmvideo(
    "flocking.mp4", model, agent_step!;
    am = bird_marker,
    framerate = 20, frames = 100,
    title = "Flocking"
)

```

LoadError: MethodError: no method matching ContinuousAgent{2}(::Int64, ::Tuple{Float64, Float64}, ::Tuple{Float64, Float64}, ::Float64, ::Float64, ::Float64, ::Float64, ::Float64, ::Float64)  
Closest candidates are:  
ContinuousAgent{D}(::Any, ::Any, ::Any) where D at ~/.julia/packages/Agents/960Tr/src/core/agents.jl:196  
Stacktrace:

---

<div class="post-metadata">

**Author:** ![Niall](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/niall/32/22517_2.png) [@Niall](https://discourse.julialang.org/u/Niall)\
**Post date:** [March 4, 2023, 7:07pm UTC](https://discourse.julialang.org/t/calculating-displacement-vectors-between-agents/95458/4 "2023-03-04T19:07:15Z")

</div>

I’m sorry Freya - I expressed myself unclearly. I intended the above code at the Julia prompt as a demonstration of how displacement vectors should work at a periodic space boundary - this demonstration is completely independent of the Flocking code.

Ultimately, now that I have found the appropriate function in the API, my point is that the Flocking model as it currently appears at the Agents website has a bug in it, and this bug can be removed if you replace this line:

```julia
heading = neighbor .- bird.pos

```

by this line:

```julia
heading = get_direction( bird.pos, neighbor)

```

Best wishes,  
Niall.
