-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodel.py
More file actions
207 lines (167 loc) · 7.65 KB
/
model.py
File metadata and controls
207 lines (167 loc) · 7.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
import mesa
from agents import Soil, Type_a, Type_b, Type_c, Type_d, Type_a_1, Type_a_2
# this function is used for the datacollector
def get_num_bacteria_per_type(model, bacteria_type):
bacteria = [a for a in model.schedule.agents if isinstance(a, bacteria_type)]
return len(bacteria)
# calculating average position for swarm movement
# There is a problem with this method when the grid is torodial
# when a swarm scouts targets on both sides of the grid at the same time
# the average is in the middle, which means, they all try to go there
# a better option might be to set the target to the median/ the most occuring position
# this function not very efficient!!!
def get_average_pos(lst):
if len(lst) == 0:
return []
x = 0
y = 0
counter = 0
for pos in lst:
x += pos[0]
y += pos[1]
counter += 1
return [(round(x/counter), round(y/counter))]
# not in use
def get_swarm_heart(swarm_id):
x = 0
y = 0
counter = 0
for cell in model.schedule.agents:
if isinstance(cell, Type_d) and cell.swarm_id==swarm_id:
x += cell.pos[0]
y += cell.pos[1]
counter += 1
return (round(x/counter), round(y/counter))
class Microbiome(mesa.Model):
"""A model with some number of agents."""
def __init__(self, num_type_a, num_type_a_1, num_type_a_2, num_type_b, num_type_c, num_type_d, type_a_population_limit, type_d_population_limit, is_torus, grid_height, grid_width):
################################
### CUSTOMIZABLE VARIABLES
################################
# grid_width and grid_height also need to be changed in server.py for visualisation:
# canvas_element = mesa.visualization.CanvasGrid(bacteria_portrayal, self.grid_width, self.grid_height, 500, 500)
self.grid_width = grid_width
self.grid_height = grid_height
# decides after how many turns the random direction of the type_d swarms changes
# prevents the swarm from going back and forth
# done in the model for the whole swarm, so it doesnt spread
self.swarm_direction_turns = 10
# decides if the swarm moves in percentage 0 = 0%, 1 = 100% --> 1 means swarm moves every time
# done in the model for the whole swarm, so it doesnt spread
self.swarm_chance_move = 1
# stops reproduction after population reaches a limit
self.type_a_population_limit = type_a_population_limit
self.type_d_population_limit = type_d_population_limit
# reproduction spread pattern, if True includes all 8 surrounding squares, False means only up/down/left/right
self.reproduction_spread_moore = True
################################
################################
################################
self.running = True
self.current_id = 1
self.step_num = 1
self.directions = ["left", "right", "up", "down"]
# Type d moves in Swarms
self.swarm_direction = []
self.swarm_target = []
self.reproduction_stop_a = False
self.reproduction_stop_d = False
for s in range(num_type_d):
self.swarm_direction.append(self.random.choice(self.directions))
self.swarm_target.append([])
self.swarm_move = True
self.grid = mesa.space.MultiGrid(self.grid_width, self.grid_height, is_torus)
# different schedulers can be found here
# https://mesa.readthedocs.io/en/latest/apis/time.html
self.schedule = mesa.time.RandomActivation(self)
# Create Soil
for i in range(self.grid.width):
for j in range(self.grid.height):
soil = Soil(self.next_id(), self, (i, j))
self.schedule.add(soil)
self.grid.place_agent(soil, (i, j))
# Create Type_a
for i in range(num_type_a):
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
a = Type_a(self.next_id(), self, (x, y))
self.schedule.add(a)
# Add the agent to a random grid cell
self.grid.place_agent(a, (x, y))
# Create Type_a_1
for i in range(num_type_a_1):
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
a = Type_a_1(self.next_id(), self, (x, y))
self.schedule.add(a)
# Add the agent to a random grid cell
self.grid.place_agent(a, (x, y))
# Create Type_a_1
for i in range(num_type_a_2):
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
a = Type_a_2(self.next_id(), self, (x, y))
self.schedule.add(a)
# Add the agent to a random grid cell
self.grid.place_agent(a, (x, y))
# Create Type_b
for i in range(num_type_b):
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
a = Type_b(self.next_id(), self, (x, y))
self.schedule.add(a)
# Add the agent to a random grid cell
self.grid.place_agent(a, (x, y))
# Create Type_c
for i in range(num_type_c):
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
a = Type_c(self.next_id(), self, (x, y))
self.schedule.add(a)
# Add the agent to a random grid cell
self.grid.place_agent(a, (x, y))
# Create Type_d
for i in range(num_type_d):
x = self.random.randrange(self.grid.width)
y = self.random.randrange(self.grid.height)
a = Type_d(self.next_id(), self, (x, y), i)
self.schedule.add(a)
# Add the agent to a random grid cell
self.grid.place_agent(a, (x, y))
self.datacollector = mesa.DataCollector(
model_reporters={
"Type_a": [get_num_bacteria_per_type, [self, Type_a]],
"Type_a_1": [get_num_bacteria_per_type, [self, Type_a_1]],
"Type_a_2": [get_num_bacteria_per_type, [self, Type_a_2]],
"Type_b": [get_num_bacteria_per_type, [self, Type_b]],
"Type_c": [get_num_bacteria_per_type, [self, Type_c]],
"Type_d": [get_num_bacteria_per_type, [self, Type_d]]
}
)
def step(self):
self.step_num += 1
# reset swarm target
for idx, target in enumerate(self.swarm_target):
# self.swarm_target[idx] = get_average_pos(target)
self.swarm_target[idx] = []
# Type_d movement is synchronised
if self.step_num % self.swarm_direction_turns == 0:
for i in range(len(self.swarm_direction)):
self.swarm_direction[i] = self.random.choice(self.directions)
# decides if type_d moves
if self.random.random() < self.swarm_chance_move:
self.swarm_move = True
else:
self.swarm_move = False
# Stopping reproduction at a certain point for performance reasons
if get_num_bacteria_per_type(self, Type_d) > self.type_d_population_limit & self.type_d_population_limit != 0:
self.reproduction_stop_d = True
else:
self.reproduction_stop_d = False
if get_num_bacteria_per_type(self, Type_a) > self.type_a_population_limit & self.type_a_population_limit != 0:
self.reproduction_stop_a = True
else:
self.reproduction_stop_a = False
# run agents
self.datacollector.collect(self)
self.schedule.step()