added live-server visualization to project
This commit is contained in:
parent
a5e03b38ac
commit
214135d063
11
agent.py
11
agent.py
@ -14,14 +14,14 @@ from typing import overload
|
||||
|
||||
class RandomWalkerAnt(Agent):
|
||||
def __init__(self, unique_id, model, look_for_chemical=None,
|
||||
energy_0=1, chemical_drop_rate_0=1, sensitvity_0=1, alpha=0.5) -> None:
|
||||
energy_0=1, chemical_drop_rate_0=1, sensitvity_0=1, alpha=0.5, drop_chemical=None) -> None:
|
||||
super().__init__(unique_id=unique_id, model=model)
|
||||
|
||||
self._next_pos : None | Coordinate = None
|
||||
|
||||
self.prev_pos : None | Coordinate = None
|
||||
self.look_for_chemical = look_for_chemical
|
||||
self.drop_chemical = None
|
||||
self.drop_chemical = drop_chemical
|
||||
self.energy : float = energy_0
|
||||
self.sensitvity : float = sensitvity_0
|
||||
self.chemical_drop_rate : float = chemical_drop_rate_0 #TODO: check whether needs to be separated into A and B
|
||||
@ -34,6 +34,10 @@ class RandomWalkerAnt(Agent):
|
||||
|
||||
def step(self):
|
||||
# follow positive gradient
|
||||
if self.prev_pos is None:
|
||||
i = np.random.choice(range(6))
|
||||
self._next_pos = self.neighbors()[i]
|
||||
return
|
||||
if self.look_for_chemical is not None:
|
||||
front_concentration = [self.model.grid.fields[self.look_for_chemical][cell] for cell in self.front_neighbors ]
|
||||
gradient = front_concentration - np.repeat(self.model.grid.fields[self.look_for_chemical][self.pos], 3)
|
||||
@ -61,8 +65,7 @@ class RandomWalkerAnt(Agent):
|
||||
def advance(self) -> None:
|
||||
self.drop_chemicals()
|
||||
self.prev_pos = self.pos
|
||||
self.pos = self._next_pos
|
||||
|
||||
self.model.grid.move_agent(self, self._next_pos)
|
||||
|
||||
# TODO: find out how to decorate with property properly
|
||||
def neighbors(self, pos=None, include_center=False):
|
||||
|
8
model.py
8
model.py
@ -33,12 +33,12 @@ class ActiveWalkerModel(Model):
|
||||
self.nest_position : Coordinate = nest_position
|
||||
self.num_max_agents = num_max_agents
|
||||
|
||||
self.decay_rates = {"A" :1,
|
||||
"B": 1,
|
||||
self.decay_rates : dict[str, float] = {"A" :0.1,
|
||||
"B": 0.1,
|
||||
}
|
||||
|
||||
for agent_id in self.get_unique_ids(num_initial_roamers):
|
||||
agent = RandomWalkerAnt(unique_id=agent_id, model=self, look_for_chemical="A")
|
||||
agent = RandomWalkerAnt(unique_id=agent_id, model=self, look_for_chemical="A", drop_chemical="A")
|
||||
self.schedule.add(agent)
|
||||
self.grid.place_agent(agent, pos=nest_position)
|
||||
|
||||
@ -64,8 +64,6 @@ class ActiveWalkerModel(Model):
|
||||
field = self.grid.fields[key]
|
||||
self.grid.fields[key] = field - self.decay_rates[key]*field
|
||||
|
||||
self.grid.step() # actually apply deposits on fields
|
||||
|
||||
self.datacollector.collect(self)
|
||||
|
||||
if self.schedule.steps >= self.max_steps:
|
||||
|
109
server.py
Executable file
109
server.py
Executable file
@ -0,0 +1,109 @@
|
||||
#!/bin/python
|
||||
"""
|
||||
server.py - Part of ants project
|
||||
|
||||
This file sets up the mesa built-in visualization server
|
||||
and runs it on file execution.
|
||||
For now it displays ant locations as well as pheromone A
|
||||
concentrations on two seperate grids
|
||||
|
||||
License: AGPL 3 (see end of file)
|
||||
(C) Alexander Bocken, Viviane Fahrni, Grace Kragho
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
from mesa.visualization.modules import CanvasHexGrid, ChartModule, CanvasGrid
|
||||
from mesa.visualization.ModularVisualization import ModularServer
|
||||
from mesa.visualization.UserParam import UserSettableParameter
|
||||
from model import ActiveWalkerModel
|
||||
from collections import defaultdict
|
||||
|
||||
def setup():
|
||||
# Set the model parameters
|
||||
params = {
|
||||
"width": 50, "height": 50,
|
||||
"num_max_agents" : 100,
|
||||
"nest_position" : (25,25),
|
||||
"num_initial_roamers" : 5,
|
||||
}
|
||||
|
||||
|
||||
class CanvasHexGridMultiAgents(CanvasHexGrid):
|
||||
"""
|
||||
A modification of CanvasHexGrid to not run visualization functions on all agents
|
||||
but on all grid positions instead
|
||||
"""
|
||||
package_includes = ["HexDraw.js", "CanvasHexModule.js", "InteractionHandler.js"]
|
||||
portrayal_method = None # Portrayal function
|
||||
canvas_width = 500
|
||||
canvas_height = 500
|
||||
|
||||
def __init__(self, portrayal_method, grid_width, grid_height, canvas_width=500, canvas_height=500,):
|
||||
super().__init__(portrayal_method, grid_width, grid_height, canvas_width, canvas_height)
|
||||
|
||||
def render(self, model):
|
||||
grid_state = defaultdict(list)
|
||||
for x in range(model.grid.width):
|
||||
for y in range(model.grid.height):
|
||||
portrayal = self.portrayal_method(model, (x, y))
|
||||
if portrayal:
|
||||
portrayal["x"] = x
|
||||
portrayal["y"] = y
|
||||
grid_state[portrayal["Layer"]].append(portrayal)
|
||||
|
||||
return grid_state
|
||||
|
||||
|
||||
def get_color(level, normalization):
|
||||
"""
|
||||
level: level to calculate color between white and black (linearly)
|
||||
normalization: value for which we want full black color
|
||||
"""
|
||||
rgb = int(255 - level * 255 / normalization)
|
||||
mono = f"{rgb:0{2}x}" # hex value of rgb value with fixed length 2
|
||||
rgb = f"#{3*mono}"
|
||||
return rgb
|
||||
|
||||
def portray_ant_density(model, pos):
|
||||
return {
|
||||
"Shape": "hex",
|
||||
"r": 1,
|
||||
"Filled": "true",
|
||||
"Layer": 0,
|
||||
"x": pos[0],
|
||||
"y": pos[1],
|
||||
"Color": get_color(level=len(model.grid[pos]), normalization=5)
|
||||
}
|
||||
|
||||
def portray_pheromone_density(model, pos):
|
||||
return {
|
||||
"Shape": "hex",
|
||||
"r": 1,
|
||||
"Filled": "true",
|
||||
"Layer": 0,
|
||||
"x": pos[0],
|
||||
"y": pos[1],
|
||||
"Color": get_color(level=model.grid.fields["A"][pos], normalization=3)
|
||||
}
|
||||
|
||||
|
||||
|
||||
width = params['width']
|
||||
height = params['height']
|
||||
pixel_ratio = 10
|
||||
grid_ants = CanvasHexGridMultiAgents(portray_ant_density, width, height, width*pixel_ratio, height*pixel_ratio)
|
||||
grid_pheromones = CanvasHexGridMultiAgents(portray_pheromone_density, width, height, width*pixel_ratio, height*pixel_ratio)
|
||||
return ModularServer(ActiveWalkerModel, [grid_ants, grid_pheromones],
|
||||
"Active Random Walker Ants", params)
|
||||
|
||||
if __name__ == "__main__":
|
||||
server = setup()
|
||||
server.launch()
|
||||
|
||||
"""
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <https://www.gnu.org/licenses/>
|
||||
"""
|
Loading…
Reference in New Issue
Block a user