Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Round environment #48

Merged
merged 21 commits into from
Nov 14, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
dfb9dc1
update draw walls function
vagechirkov Nov 4, 2022
ac9e493
add reflection_from_circular_wall function and tests
vagechirkov Nov 7, 2022
d08a7e3
reflect agent from the circular border
vagechirkov Nov 7, 2022
3a073dd
reflect resource from the circular border
vagechirkov Nov 7, 2022
e61ecca
minor comment
vagechirkov Nov 7, 2022
9b3e07f
ignore videos
vagechirkov Nov 7, 2022
c40ff66
run test on PR too
vagechirkov Nov 7, 2022
4fde313
test docker-image workflow
vagechirkov Nov 8, 2022
465e8bb
split GitHub action Docker CI workflow in two workflows
vagechirkov Nov 8, 2022
5f486f6
Merge branch 'develop' into round-environment
vagechirkov Nov 10, 2022
b990a13
update agent's position only ones per update
vagechirkov Nov 10, 2022
768941d
relocate resource base on its velocity
vagechirkov Nov 10, 2022
12a35dc
fix new agents generation via slider in playground
vagechirkov Nov 10, 2022
377b298
make the default patch_radius larger
vagechirkov Nov 14, 2022
b74d604
Revert "make the default patch_radius larger"
vagechirkov Nov 14, 2022
fdd57fd
refactor imports
vagechirkov Nov 14, 2022
d3359aa
fix the bug when moving agents with the mouse (use list instead of tu…
vagechirkov Nov 14, 2022
8e02862
use velocity instead of radius for relocation of the agent
vagechirkov Nov 14, 2022
887199b
relocate agents when their positions are manually changed
vagechirkov Nov 14, 2022
edf6d39
relocate resource when the positions are manually changed
vagechirkov Nov 14, 2022
09f67da
Mocking submodule variables to keep
mezdahun Nov 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/docker-image-push.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Docker Image CI

on:
push:
branches:
- develop

jobs:

build:

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Docker Login
env:
DOCKER_USER: ${{secrets.DOCKER_USER}}
DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}}
run: |
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
- name: Build the Docker image
run: docker build . --file Dockerfile --tag ${{secrets.DOCKER_USER}}/scioip34abm:latest
- name: Push Docker image to DockerHub
run: docker push ${{secrets.DOCKER_USER}}/scioip34abm:latest
19 changes: 5 additions & 14 deletions .github/workflows/docker-image.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
name: Docker Image CI

on:
push:
branches: [ develop ]
pull_request:
branches: [ develop ]
branches:
- develop

jobs:

Expand All @@ -13,14 +12,6 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- name: Docker Login
env:
DOCKER_USER: ${{secrets.DOCKER_USER}}
DOCKER_PASSWORD: ${{secrets.DOCKER_PASSWORD}}
run: |
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD
- name: Build the Docker image
run: docker build . --file Dockerfile --tag ${{secrets.DOCKER_USER}}/scioip34abm:latest
- name: Push Docker image to DockerHub
run: docker push ${{secrets.DOCKER_USER}}/scioip34abm:latest
- uses: actions/checkout@v2
- name: Build the Docker image
run: docker build . --file Dockerfile
2 changes: 1 addition & 1 deletion .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Python package

on: [push]
on: [push, pull_request]

jobs:
build:
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -245,4 +245,7 @@ cython_debug/
.idea

# ignore all copied env files
*_copy.env
*_copy.env

# ignore videos
*.mp4
33 changes: 30 additions & 3 deletions abm/projects/cooperative_signaling/cs_agent/cs_agent.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import numpy as np
import pygame

from abm.agent import supcalc
from abm.projects.cooperative_signaling.cs_agent.cs_supcalc import random_walk, \
F_reloc_LR
from abm.projects.cooperative_signaling.cs_agent.cs_supcalc import \
random_walk, F_reloc_LR, reflection_from_circular_wall
from abm.agent.agent import Agent
from abm.contrib import colors

Expand Down Expand Up @@ -301,3 +300,31 @@ def prove_velocity(self, velocity_limit=1):
if np.abs(self.velocity) > velocity_limit:
# stopping agent if too fast during exploration
self.velocity = 1

def reflect_from_walls(self):
"""
Reflecting agent from the circle arena border.
"""
# x coordinate - x of the center point of the circle
x = self.position[0] + self.radius
dx = x - (self.WIDTH / 2 + self.window_pad)
# y coordinate - y of the center point of the circle
y = self.position[1] + self.radius
dy = y - (self.HEIGHT / 2 + self.window_pad)
# radius of the environment
e_r = self.HEIGHT / 2

# return if the agent has not reached the boarder
if np.linalg.norm([dx, dy]) + self.radius < e_r:
return

# reflect the agent from the boarder
self.orientation = reflection_from_circular_wall(
dx, dy, self.orientation)

# make orientation between 0 and 2pi
self.prove_orientation()

# relocate the agent back inside the circle
self.position[0] += (self.radius / 2) * np.cos(self.orientation)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are changing the position of the agents twice in a single time step. Once in self.update() and once here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about this solution? b990a13

self.position[1] -= (self.radius / 2) * np.sin(self.orientation)
36 changes: 36 additions & 0 deletions abm/projects/cooperative_signaling/cs_agent/cs_supcalc.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import numpy as np
import pygame

from abm.contrib import movement_params

Expand Down Expand Up @@ -36,3 +37,38 @@ def F_reloc_LR(vel_now, V_now, v_desired=None, theta_max=None):
D_leftright = left_excitation - right_excitation
theta = D_leftright * theta_max
return (v_desired - vel_now), theta


def reflection_from_circular_wall(dx, dy, orientation):
"""
Calculating the reflection of the agent from the circle arena border.
SEE: https://stackoverflow.com/questions/54543170/angle-reflexion-for-bouncing-ball-in-a-circle

:param dx: x coordinate of the agent minus center of the circle
:param dy: y coordinate of the agent minus center of the circle
:param orientation: orientation of the agent
:return: new orientation of the agent
"""
# normal vector of the circle
c_norm = (pygame.math.Vector2(dx, dy)).normalize()
# incident vector: the current direction vector of the bouncing agent
vec_i = pygame.math.Vector2(np.cos(orientation), np.sin(orientation))
# orientation inside the circle
i_orientation = np.pi + np.arctan2(vec_i[1], vec_i[0])

# reflection vector: outgoing direction vector of the bouncing agent
vec_r = vec_i - 2 * c_norm.dot(vec_i) * c_norm
# np.degrees(self.orientation)
new_orientation = np.pi + np.arctan2(vec_r[1], vec_r[0])

# make sure that the new orientation points inside the circle and not too
# flat to the border
if np.abs(new_orientation - i_orientation) > np.pi / 4:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand this fixes the behavior, but I am wondering why it is necessary.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would guess it has something to do with the curvature of the boundary and the step size per update 😅

new_orientation = i_orientation
# make sure that the change of the orientation is not too big; this prevents
# the agent from "jumping" over the border and other wierd behavior when the
# agent changes its orientation too ofter
elif np.abs(new_orientation - orientation) > np.pi / 4:
new_orientation = i_orientation

return new_orientation
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,24 @@ def test_random_walk():

assert dvel == 1.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for me random walk test fails can you please check?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah it is because the env parameters, we might want to mock this so that a new local env file won't influence the test results

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is strange because all the tests in the workflow passed 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you replace the .env file (i.e. you are after running the playground tool) the tests won't pass. Or do they pass for you even with a new .env file?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I never had any problems with tests before or after running the playground 😅🤔

assert dtheta == -0.0752759286915825


def test_reflection_from_circular_wall():
"""Test reflection_from_circular_wall()"""

new_orientation = cs_supcalc.reflection_from_circular_wall(
0, 1, np.pi / 2)
assert new_orientation == np.pi * 3 / 2

new_orientation = cs_supcalc.reflection_from_circular_wall(
1, 0, np.pi)
assert new_orientation == np.pi * 2

# test very flat reflection angle
orient = np.pi + np.pi / 6
vec_i = [np.cos(orient), np.sin(orient)]
# orientation inside the circle
i_orientation = np.pi + np.arctan2(vec_i[1], vec_i[0])
new_orientation = cs_supcalc.reflection_from_circular_wall(
0, 1, orient)
assert new_orientation == i_orientation
74 changes: 27 additions & 47 deletions abm/projects/cooperative_signaling/cs_environment/cs_resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

from abm.contrib import colors
from abm.environment.rescource import Rescource
from abm.projects.cooperative_signaling.cs_agent.cs_supcalc import random_walk
from abm.projects.cooperative_signaling.cs_agent.cs_supcalc import random_walk, \
reflection_from_circular_wall


class CSResource(Rescource):
Expand Down Expand Up @@ -44,55 +45,34 @@ def prove_orientation(self):
self.orientation = self.orientation - 2 * np.pi

def reflect_from_walls(self):
"""reflecting agent from environment boundaries according to a desired
x, y coordinate. If this is over any
boundaries of the environment, the agents position and orientation will
be changed such that the agent is
reflected from these boundaries."""

# Boundary conditions according to center of agent (simple)
"""
Reflecting resource from the circle arena border. Analogous to CSAgent
reflect_from_walls() method.
"""
# x coordinate - x of the center point of the circle
x = self.position[0] + self.radius
dx = x - (self.WIDTH / 2 + self.window_pad)
# y coordinate - y of the center point of the circle
y = self.position[1] + self.radius
dy = y - (self.HEIGHT / 2 + self.window_pad)
# radius of the environment
e_r = self.HEIGHT / 2

# return if the agent has not reached the boarder
if np.linalg.norm([dx, dy]) + self.radius < e_r:
return

# reflect the agent from the boarder
self.orientation = reflection_from_circular_wall(
dx, dy, self.orientation)

# make orientation between 0 and 2pi
self.prove_orientation()

# Reflection from left wall
if x < self.boundaries_x[0]:
self.position[0] = self.boundaries_x[0] - self.radius

if np.pi / 2 <= self.orientation < np.pi:
self.orientation -= np.pi / 2
elif np.pi <= self.orientation <= 3 * np.pi / 2:
self.orientation += np.pi / 2
self.prove_orientation() # bounding orientation into 0 and 2pi

# Reflection from right wall
if x > self.boundaries_x[1]:

self.position[0] = self.boundaries_x[1] - self.radius - 1

if 3 * np.pi / 2 <= self.orientation < 2 * np.pi:
self.orientation -= np.pi / 2
elif 0 <= self.orientation <= np.pi / 2:
self.orientation += np.pi / 2
self.prove_orientation() # bounding orientation into 0 and 2pi

# Reflection from upper wall
if y < self.boundaries_y[0]:
self.position[1] = self.boundaries_y[0] - self.radius

if np.pi / 2 <= self.orientation <= np.pi:
self.orientation += np.pi / 2
elif 0 <= self.orientation < np.pi / 2:
self.orientation -= np.pi / 2
self.prove_orientation() # bounding orientation into 0 and 2pi

# Reflection from lower wall
if y > self.boundaries_y[1]:
self.position[1] = self.boundaries_y[1] - self.radius - 1
if 3 * np.pi / 2 <= self.orientation <= 2 * np.pi:
self.orientation += np.pi / 2
elif np.pi <= self.orientation < 3 * np.pi / 2:
self.orientation -= np.pi / 2
self.prove_orientation() # bounding orientation into 0 and 2pi
# relocate the agent back inside the circle
relocation = np.min([(self.radius / 2), 5])
vagechirkov marked this conversation as resolved.
Show resolved Hide resolved
self.position[0] += relocation * np.cos(self.orientation)
self.position[1] -= relocation * np.sin(self.orientation)

self.center = (
self.position[0] + self.radius, self.position[1] + self.radius)
Expand Down
45 changes: 32 additions & 13 deletions abm/projects/cooperative_signaling/cs_simulation/cs_sims.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,19 +94,9 @@ def add_new_resource_patch(self, force_id=None):
"Reached timeout while trying to create resources without "
"overlap!")
radius = self.resc_radius
if self.allow_border_patch_overlap:
# allowing patches to overlap arena borders (maximum overlap is
# radius of patch)
x = np.random.randint(self.window_pad - radius,
self.WIDTH + self.window_pad - radius)
y = np.random.randint(self.window_pad - radius,
self.HEIGHT + self.window_pad - radius)
else:
# for inhibiting patches to overlap arena borders
x = np.random.randint(self.window_pad,
self.WIDTH + self.window_pad - 2 * radius)
y = np.random.randint(self.window_pad,
self.HEIGHT + self.window_pad - 2 * radius)
# spawning resource in the middle of the environment
x = self.WIDTH / 2 + self.window_pad
y = self.HEIGHT / 2 + self.window_pad
units = np.random.randint(self.min_resc_units, self.max_resc_units)
quality = np.random.uniform(self.min_resc_quality,
self.max_resc_quality)
Expand Down Expand Up @@ -170,6 +160,35 @@ def add_new_agent(self, id, x, y, orient, with_proove=False,
self.agents.add(agent)
agent_proven = True

def create_agents(self):
"""
Creating agents according to how the simulation class was initialized
"""
for i in range(self.N):
orient = np.random.uniform(0, 2 * np.pi)
dist = np.random.rand() * (
self.HEIGHT / 2 - 2 * self.window_pad - self.agent_radii)
x = np.cos(orient) * dist + self.WIDTH / 2
vagechirkov marked this conversation as resolved.
Show resolved Hide resolved
y = np.sin(orient) * dist + self.HEIGHT / 2
if not self.heterogen_agents:
# create agents according to environment variables homogeneously
self.add_new_agent(i, x, y, orient)
else:
self.add_new_agent(
i, x, y, orient,
behave_params=self.agent_behave_param_list[i])

def draw_walls(self):
"""
Drawing walls on the arena according to initialization, i.e. width,
height and padding
"""
pygame.draw.circle(self.screen, colors.BLACK,
center=[self.WIDTH / 2 + self.window_pad,
self.HEIGHT / 2 + self.window_pad],
radius=self.HEIGHT / 2,
width=1)

def start(self):
start_time = datetime.now()
print(f"Running simulation start method!")
Expand Down