Skip to content

Commit

Permalink
Merge pull request #70 from scioip34/feature/vswrm
Browse files Browse the repository at this point in the history
Feature/vswrm
  • Loading branch information
mezdahun authored Nov 20, 2023
2 parents 01459b6 + 1b61cb7 commit 43b6ae2
Show file tree
Hide file tree
Showing 36 changed files with 4,576 additions and 301 deletions.
168 changes: 67 additions & 101 deletions .env
Original file line number Diff line number Diff line change
@@ -1,101 +1,67 @@
# Basic simulation parameters

# Number of agents and resc. patches
N = 3
N_RESOURCES = 10

# Simulation time
T = 1000

# Framerate (only matter if visualization is turned on)
INIT_FRAMERATE = 25

# Visualization ON/OFF
WITH_VISUALIZATION = 1

# Resolution (px) of agents' visual projection fields
VISUAL_FIELD_RESOLUTION = 1200

# Enviornment size (width and height in px)
ENV_WIDTH = 600
ENV_HEIGHT = 600

# Agent and Resource sizes
RADIUS_AGENT = 10
RADIUS_RESOURCE = 45
MIN_RESOURCE_PER_PATCH = 400
MAX_RESOURCE_PER_PATCH = 450
REGENERATE_PATCHES = 1
PATCH_BORDER_OVERLAP = 1

# Exploitation
# max consumption of an agent per timestep
AGENT_CONSUMPTION = 1
# resource patch quality
MIN_RESOURCE_QUALITY = 0.05
MAX_RESOURCE_QUALITY = 0.3
TELEPORT_TO_MIDDLE = 0
GHOST_WHILE_EXPLOIT = 1
AGENT_AGENT_COLLISION = 1
PATCHWISE_SOCIAL_EXCLUSION =1

# Vision
# fov is symmetric and defined with percent of pi. e.g
# if 0.6 then fov is (-0.6*pi, 0.6*pi). 1 is full 360 degree vision
AGENT_FOV = 0.45
VISION_RANGE = 200
VISUAL_EXCLUSION = 1

# Visualize agents' visual field on screen by default or when return is pressed
SHOW_VISUAL_FIELDS = 0
SHOW_VISUAL_FIELDS_RETURN = 1
SHOW_VISION_RANGE = 1

# Time needed to acquire info from env and initial probability for pooling process
POOLING_TIME = 0
POOLING_PROBABILITY = 0.05

# Monitoring Related parameters (True only tested on Ubuntu machines with
# initialized grafana and ifdb instances as in readme)
# log data in influxdb
USE_IFDB_LOGGING = 0
# logs data in RAM
USE_RAM_LOGGING = 1
# using zarr compression
USE_ZARR_FORMAT = 1
# saves csv files (if ifdb logging is used, json files otherwise)
SAVE_CSV_FILES = 0

# Decision process parameters
DEC_TW = 0.5
DEC_EPSW = 3
DEC_GW = 0.085
DEC_BW = 0
DEC_WMAX = 1

DEC_TU = 0.5
DEC_EPSU = 3
DEC_GU = 0.085
DEC_BU = 0
DEC_UMAX = 1

DEC_SWU = 0.25
DEC_SUW = 0.01

DEC_TAU = 10
DEC_FN = 2
DEC_FR = 1

# Movement parameters
# Exploration
MOV_EXP_VEL_MIN = 1
MOV_EXP_VEL_MAX = 1
MOV_EXP_TH_MIN = -0.3
MOV_EXP_TH_MAX = 0.3

# Relocation
MOV_REL_DES_VEL = 1
MOV_REL_TH_MAX = 0.5

# Exploitation
CONS_STOP_RATIO = 0.08
N=10
N_RESOURCES=1
T=5000
INIT_FRAMERATE=25
WITH_VISUALIZATION=0
VISUAL_FIELD_RESOLUTION=320
ENV_WIDTH=900
ENV_HEIGHT=900
RADIUS_AGENT=10
RADIUS_RESOURCE=20
MIN_RESOURCE_PER_PATCH=100
MAX_RESOURCE_PER_PATCH=-1
REGENERATE_PATCHES=1
PATCH_BORDER_OVERLAP=1
MAX_SPEED=1.5
AGENT_CONSUMPTION=1
MIN_RESOURCE_QUALITY=0.25
MAX_RESOURCE_QUALITY=-1
TELEPORT_TO_MIDDLE=0
GHOST_WHILE_EXPLOIT=1
AGENT_AGENT_COLLISION=0
PATCHWISE_SOCIAL_EXCLUSION=1
AGENT_FOV=0.5
VISION_RANGE=2000
VISUAL_EXCLUSION=0
SHOW_VISUAL_FIELDS=0
SHOW_VISUAL_FIELDS_RETURN=0
SHOW_VISION_RANGE=0
POOLING_TIME=0
POOLING_PROBABILITY=0.05
USE_IFDB_LOGGING=1
USE_RAM_LOGGING=1
USE_ZARR_FORMAT=1
SAVE_CSV_FILES=1
DEC_TW=0.5
DEC_EPSW=0
DEC_GW=0.085
DEC_BW=0
DEC_WMAX=1
DEC_TU=0.5
DEC_EPSU=1
DEC_GU=0.085
DEC_BU=0
DEC_UMAX=1
DEC_SWU=0
DEC_SUW=0
DEC_TAU=10
DEC_FN=0.5
DEC_FR=0.5
MOV_EXP_VEL_MIN=3
MOV_EXP_VEL_MAX=3
MOV_EXP_TH_MIN=-0.5
MOV_EXP_TH_MAX=0.5
MOV_REL_DES_VEL=3
MOV_REL_TH_MAX=1.8
MEMORY_DEPTH=1
CONS_STOP_RATIO=0.175
APP_VERSION=VisualFlocking
VF_GAM=0.1
VF_V0=1
VF_ALP0=0
VF_ALP1=0.0014
VF_ALP2=0
VF_BET0=0
VF_BET1=0.0014
VF_BET2=0
SAVE_ROOT_DIR=abm/data/simulation_data/VFinfinite/batch_0
93 changes: 10 additions & 83 deletions abm/agent/supcalc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,89 +2,7 @@
calc.py : Supplementary methods and calculations necessary for agents
"""
import numpy as np
from scipy import integrate
from abm.contrib import vswrm, movement_params


# Functions needed for VSWRM functionality
def VSWRM_flocking_state_variables(vel_now, Phi, V_now, t_now=None, V_prev=None, t_prev=None):
"""Calculating state variables of a given agent according to the main algorithm as in
https://advances.sciencemag.org/content/6/6/eaay0792.
Args:
vel_now: current speed of the agent
V_now: current binary visual projection field array
Phi: linspace numpy array of visual field axis
t_now: current time
V_prev: previous binary visual projection field array
t_prev: previous time
Returns:
dvel: temporal change in agent velocity
dpsi: temporal change in agent heading angle
"""
# # Deriving over t
# if V_prev is not None and t_prev is not None and t_now is not None:
# dt = t_now - t_prev
# logger.debug('Movement calculation called with NONE as time-related parameters.')
# joined_V = np.vstack((V_prev, t_prev))
# dt_V = dt_V_of(dt, joined_V)
# else:
# dt_V = np.zeros(len(Phi))

dt_V = np.zeros(len(Phi))

# Deriving over Phi
dPhi_V = dPhi_V_of(Phi, V_now)

# Calculating series expansion of functional G
G_vel = (-V_now + vswrm.ALP2 * dt_V)

# Spikey parts shall be handled separately because of numerical integration
G_vel_spike = np.square(dPhi_V)

G_psi = (-V_now + vswrm.BET2 * dt_V)

# Spikey parts shall be handled separately because of numerical integration
G_psi_spike = np.square(dPhi_V)

# Calculating change in velocity and heading direction
dPhi = Phi[-1] - Phi[-2]
FOV_rescaling_cos = 1
FOV_rescaling_sin = 1

# print(f"alp0 : {vswrm.ALP0 * integrate.trapz(np.cos(FOV_rescaling_cos * Phi) * G_vel, Phi)}", )
# print(f'alp1 : {vswrm.ALP0 * vswrm.ALP1 * np.sum(np.cos(Phi) * G_vel_spike) * dPhi}')

dvel = vswrm.GAM * (vswrm.V0 - vel_now) + \
vswrm.ALP0 * integrate.trapz(np.cos(FOV_rescaling_cos * Phi) * G_vel, Phi) + \
vswrm.ALP0 * vswrm.ALP1 * np.sum(np.cos(Phi) * G_vel_spike) * dPhi
dpsi = vswrm.BET0 * integrate.trapz(np.sin(Phi) * G_psi, Phi) + \
vswrm.BET0 * vswrm.BET1 * np.sum(np.sin(FOV_rescaling_sin * Phi) * G_psi_spike) * dPhi

return dvel, dpsi


def dPhi_V_of(Phi, V):
"""Calculating derivative of VPF according to Phi visual angle array at a given timepoint t
Args:
Phi: linspace numpy array of visual field axis
V: binary visual projection field array
Returns:
dPhi_V: derivative array of V w.r.t Phi
"""
# circular padding for edge cases
padV = np.pad(V, (1, 1), 'wrap')
dPhi_V_raw = np.diff(padV)

# we want to include non-zero value if it is on the edge
if dPhi_V_raw[0] > 0 and dPhi_V_raw[-1] > 0:
dPhi_V_raw = dPhi_V_raw[0:-1]

else:
dPhi_V_raw = dPhi_V_raw[1:, ...]

dPhi_V = dPhi_V_raw / (Phi[-1] - Phi[-2])
return dPhi_V
from abm.contrib import movement_params


def find_nearest(array, value):
Expand Down Expand Up @@ -128,6 +46,15 @@ def random_walk(desired_vel=None):
movement_params.exp_theta_max)
return dvel, dtheta

def distance_torus(p0, p1, dimensions):
"""Calculating distance between 2 2D points p0 and p1 as nparrays in an arena
with dimensions as in dimensions with infinite boundary conditions.
po and p1 can be a set of 2D coordinates e.g. np.array([[x0, y0],[x1, y1],[x2, y2]])
"""
delta = np.abs(p0 - p1)
delta = np.where(delta > 0.5 * dimensions, delta - dimensions, delta)
return np.sqrt((delta ** 2).sum(axis=1))


def distance_coords(x1, y1, x2, y2, vectorized=False):
"""Distance between 2 points in 2D space calculated from point coordinates.
Expand Down
108 changes: 108 additions & 0 deletions abm/app_visual_flocking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import os
import shutil
from pathlib import Path

from contextlib import ExitStack
from dotenv import dotenv_values

from abm.app import save_isims_env
from abm.projects.visual_flocking.vf_simulation.vf_isims import VFPlaygroundSimulation
from abm.projects.visual_flocking.vf_contrib.vf_playgroundtool import setup_visflock_playground
from abm.projects.visual_flocking.vf_simulation.vf_sims import VFSimulation


def setup_environment():
EXP_NAME = os.getenv("EXPERIMENT_NAME", "visual_flocking")
EXP_NAME_COPY = f"{EXP_NAME}_copy"
os.path.dirname(os.path.realpath(__file__))
root_abm_dir = Path(__file__).parent.parent
env_file_dir = root_abm_dir / "abm" / "projects" / "visual_flocking" # Path(__file__).parent
env_path = env_file_dir / f"{EXP_NAME}.env"
env_path_copy = env_file_dir / f"{EXP_NAME_COPY}.env"
# make a duplicate of the env file to be used by the playground
shutil.copyfile(env_path, env_path_copy)
envconf = dotenv_values(env_path)
return env_file_dir, EXP_NAME_COPY, envconf


def start_playground():
"""starting simulation with interactive interface"""
env_file_dir, EXP_NAME_COPY, envconf = setup_environment()
# changing env file according to playground default parameters before
# running any component of the SW
pgt = setup_visflock_playground()
save_isims_env(env_file_dir, EXP_NAME_COPY, pgt, envconf)
# Start interactive simulation
sim = VFPlaygroundSimulation()
sim.start()


def start(parallel=False, headless=False, agent_behave_param_list=None):
"""starting simulation without interactive interface"""
# Define root abm directory from which env file is read out
root_abm_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))

# Finding env file
EXP_NAME = os.getenv("EXPERIMENT_NAME", "")
env_path = os.path.join(root_abm_dir, f"{EXP_NAME}.env")
if os.path.isfile(env_path):
print(f"Read env vars from {env_path}")
envconf = dotenv_values(env_path)
app_version = envconf.get("APP_VERSION", "Base")
if app_version != "VisualFlocking":
raise Exception(".env file was not created for project visual "
"flocking or no APP_VERSION parameter found!")
else:
raise Exception(f"Could not find .env file under path {env_path}")

# Initializing virtual display
window_pad = 30
vscreen_width = int(float(envconf["ENV_WIDTH"])) + 2 * window_pad + 10
vscreen_height = int(float(envconf["ENV_HEIGHT"])) + 2 * window_pad + 10

# Running headless simulation on virtual display
if headless:
# required to start pygame in headless mode
os.environ['SDL_VIDEODRIVER'] = 'dummy'
from xvfbwrapper import Xvfb

with ExitStack() if not headless else Xvfb(width=vscreen_width, height=vscreen_height) as xvfb:
sim = VFSimulation(N=int(float(envconf["N"])),
T=int(float(envconf["T"])),
v_field_res=int(envconf["VISUAL_FIELD_RESOLUTION"]),
agent_fov=float(envconf['AGENT_FOV']),
framerate=int(float(envconf["INIT_FRAMERATE"])),
with_visualization=bool(int(float(envconf["WITH_VISUALIZATION"]))),
width=int(float(envconf["ENV_WIDTH"])),
height=int(float(envconf["ENV_HEIGHT"])),
show_vis_field=bool(int(float(envconf["SHOW_VISUAL_FIELDS"]))),
show_vis_field_return=bool(int(envconf['SHOW_VISUAL_FIELDS_RETURN'])),
pooling_time=int(float(envconf["POOLING_TIME"])),
pooling_prob=float(envconf["POOLING_PROBABILITY"]),
agent_radius=int(float(envconf["RADIUS_AGENT"])),
N_resc=int(float(envconf["N_RESOURCES"])),
allow_border_patch_overlap=bool(int(float(envconf["PATCH_BORDER_OVERLAP"]))),
min_resc_perpatch=int(float(envconf["MIN_RESOURCE_PER_PATCH"])),
max_resc_perpatch=int(float(envconf["MAX_RESOURCE_PER_PATCH"])),
min_resc_quality=float(envconf["MIN_RESOURCE_QUALITY"]),
max_resc_quality=float(envconf["MAX_RESOURCE_QUALITY"]),
patch_radius=int(float(envconf["RADIUS_RESOURCE"])),
regenerate_patches=bool(int(float(envconf["REGENERATE_PATCHES"]))),
agent_consumption=int(float(envconf["AGENT_CONSUMPTION"])),
ghost_mode=bool(int(float(envconf["GHOST_WHILE_EXPLOIT"]))),
patchwise_exclusion=bool(int(float(envconf["PATCHWISE_SOCIAL_EXCLUSION"]))),
teleport_exploit=bool(int(float(envconf["TELEPORT_TO_MIDDLE"]))),
vision_range=int(float(envconf["VISION_RANGE"])),
visual_exclusion=bool(int(float(envconf["VISUAL_EXCLUSION"]))),
show_vision_range=bool(int(float(envconf["SHOW_VISION_RANGE"]))),
use_ifdb_logging=bool(int(float(envconf["USE_IFDB_LOGGING"]))),
use_ram_logging=bool(int(float(envconf["USE_RAM_LOGGING"]))),
save_csv_files=bool(int(float(envconf["SAVE_CSV_FILES"]))),
use_zarr=bool(int(float(envconf["USE_ZARR_FORMAT"]))),
parallel=parallel,
window_pad=window_pad,
agent_behave_param_list=agent_behave_param_list,
collide_agents=bool(int(float(envconf["AGENT_AGENT_COLLISION"])))
)
sim.write_batch_size = 100
sim.start()
2 changes: 1 addition & 1 deletion abm/contrib/ifdb_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
if WRITE_EACH_POINT is not None:
write_batch_size = 1
else:
T = float(int(envconf["T"]))
T = float(int(envconf.get("T", 1000)))
if T <= 1000:
write_batch_size = T
else:
Expand Down
Loading

0 comments on commit 43b6ae2

Please sign in to comment.