add scalarfields on grid
This commit is contained in:
parent
808dc6f78c
commit
1952198fad
30
agent.py
30
agent.py
@ -13,43 +13,57 @@ from mesa.space import Coordinate
|
||||
|
||||
class RandomWalkerAnt(Agent):
|
||||
def __init__(self, unique_id, model, do_follow_chemical_A=True,
|
||||
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) -> None:
|
||||
super().__init__(unique_id=unique_id, model=model)
|
||||
|
||||
self._next_pos : None | Coordinate = None
|
||||
|
||||
self.prev_pos = None
|
||||
self.prev_pos : None | Coordinate = None
|
||||
self.do_follow_chemical_A : bool = True # False -> follow_chemical_B = True
|
||||
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
|
||||
self.alpha = alpha
|
||||
|
||||
|
||||
def sensitvity_to_concentration(self, prop : float) -> float:
|
||||
# TODO
|
||||
return prop
|
||||
|
||||
|
||||
def step(self):
|
||||
# Calculate where next ant location should be and store in _next_pos
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def drop_chemicals(self):
|
||||
# drop chemicals (depending on current state) on concentration field
|
||||
# TODO
|
||||
# use self.model.grid.add_to_field(key, value, pos) to not interfere with other ants
|
||||
pass
|
||||
|
||||
def advance(self) -> None:
|
||||
self.drop_chemicals()
|
||||
self.pos = self._next_pos
|
||||
|
||||
|
||||
@property
|
||||
def front_neighbors(self):
|
||||
if self.prev_pos is not None:
|
||||
assert(self.pos is not None)
|
||||
x, y = self.pos
|
||||
x_prev, y_prev = self.prev_pos
|
||||
dx, dy = x - x_prev, y - y_prev
|
||||
front = [
|
||||
front = np.array([
|
||||
(x, y + dy),
|
||||
(x + dx, y),
|
||||
(x + dx, y + dy),
|
||||
]
|
||||
(x + dx, y),
|
||||
])
|
||||
return front #TODO: verify (do we need to sperate into even/odd?)
|
||||
else:
|
||||
# TODO: return all neighbors or raise Exception?
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
"""
|
||||
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.
|
||||
|
||||
|
1
main.py
1
main.py
@ -32,6 +32,7 @@ def main():
|
||||
agent.do_follow_chemical_A = False
|
||||
agent.prev_pos = (9,10)
|
||||
print(agent.front_neighbors)
|
||||
|
||||
print(agent.pos, agent.unique_id, agent.do_follow_chemical_A)
|
||||
|
||||
|
||||
|
30
model.py
30
model.py
@ -11,25 +11,37 @@ License: AGPL 3 (see end of file)
|
||||
import numpy as np
|
||||
from mesa.model import Model
|
||||
from mesa.space import Coordinate, HexGrid, Iterable
|
||||
from multihex import MultiHexGrid
|
||||
from multihex import MultiHexGrid, MultiHexGridScalarFields
|
||||
from mesa.time import SimultaneousActivation
|
||||
from mesa.datacollection import DataCollector
|
||||
from agent import RandomWalkerAnt
|
||||
from agent import Pheromone
|
||||
|
||||
class ActiveWalkerModel(Model):
|
||||
# TODO: separate food and source into new agents?
|
||||
# TODO: pheromone concentrations as well as agents?
|
||||
def __init__(self, width : int, height : int , num_max_agents : int,
|
||||
num_initial_roamers : int,
|
||||
nest_position : Coordinate,
|
||||
max_steps:int=1000) -> None:
|
||||
super().__init__()
|
||||
fields={"A" : True, # key : also have _next prop (for no interference in step)
|
||||
"B": True,
|
||||
"nests": False,
|
||||
"food" : False,
|
||||
}
|
||||
self.schedule = SimultaneousActivation(self)
|
||||
self.grid = MultiHexGrid(width=width, height=height, torus=True) # TODO: replace with MultiHexGrid
|
||||
self._unique_id_counter : int = -1 # only touch via get_unique_id() or get_unique_ids(num_ids)
|
||||
self.grid = MultiHexGridScalarFields(width=width, height=height, torus=True, fields=fields)
|
||||
self._unique_id_counter = -1
|
||||
|
||||
self.max_steps = max_steps
|
||||
self.nest_position : Coordinate = nest_position
|
||||
self.num_max_agents = num_max_agents
|
||||
|
||||
self.decay_rates = {"A" :1,
|
||||
"B": 1,
|
||||
}
|
||||
|
||||
for agent_id in self.get_unique_ids(num_initial_roamers):
|
||||
agent = RandomWalkerAnt(unique_id=agent_id, model=self, do_follow_chemical_A=True)
|
||||
self.schedule.add(agent)
|
||||
@ -41,8 +53,18 @@ class ActiveWalkerModel(Model):
|
||||
)
|
||||
self.datacollector.collect(self) # keep at end of __init___
|
||||
|
||||
|
||||
|
||||
def step(self):
|
||||
self.schedule.step()
|
||||
self.schedule.step() # step() and advance() all agents
|
||||
|
||||
# apply decay rate on pheromone levels
|
||||
for key in ("A", "B"):
|
||||
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:
|
||||
|
27
multihex.py
27
multihex.py
@ -12,6 +12,7 @@ License: AGPL 3 (see end of file)
|
||||
from mesa.space import HexGrid
|
||||
from mesa.agent import Agent
|
||||
import numpy as np
|
||||
import numpy.typing as npt
|
||||
from mesa.space import Coordinate, accept_tuple_argument
|
||||
import itertools
|
||||
from typing import (
|
||||
@ -91,6 +92,32 @@ class MultiHexGrid(HexGrid):
|
||||
)
|
||||
|
||||
|
||||
class MultiHexGridScalarFields(MultiHexGrid):
|
||||
def __init__(self, fields: dict[str, bool], width : int, height : int, torus : bool, scalar_initial_value : float=0) -> None:
|
||||
super().__init__(width=width, height=height, torus=torus)
|
||||
self._field_props = fields
|
||||
|
||||
self.fields : dict[str, npt.NDArray[np.float_]] = {}
|
||||
|
||||
for key, is_step_field in fields.items():
|
||||
self.fields[key] = np.ones((width, height)).astype(float) * scalar_initial_value
|
||||
if is_step_field:
|
||||
self.fields[f"_next_{key}"] = np.zeros((width, height)).astype(float)
|
||||
|
||||
def reset_field(self, key : str) -> None:
|
||||
self.fields[key] = np.zeros((self.width, self.height))
|
||||
|
||||
def add_to_field(self, field_key : str, value : float, pos : Coordinate) -> None:
|
||||
if self._field_props[field_key]:
|
||||
self.fields[f"_next_{field_key}"][pos] += value
|
||||
else:
|
||||
self.fields[field_key][pos] += value
|
||||
|
||||
def step(self) -> None:
|
||||
for key, is_step_field in self._field_props.items():
|
||||
if is_step_field:
|
||||
self.fields[key] += self.fields[f"_next_{key}"]
|
||||
self.reset_field(f"_next_{key}")
|
||||
|
||||
"""
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user