Skip to content

Commit f5070b7

Browse files
committed
updates
1 parent 5759cb3 commit f5070b7

File tree

6 files changed

+1288
-6
lines changed

6 files changed

+1288
-6
lines changed

docs/examples.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@
33

44

55
```{toctree}
6-
:maxdepth: 2
6+
:maxdepth: 1
77
8-
<examples/boid_flockers>
9-
<examples/virus_on_network>
10-
<examples/conways_game_of_life>
11-
<examples/schelling>
12-
<examples/boltzmann_wealth_model>
8+
./examples/boid_flockers <examples/boid_flockers>
9+
./examples/virus_on_network <examples/virus_on_network>
10+
./examples/conways_game_of_life <examples/conways_game_of_life>
11+
./examples/schelling <examples/schelling>
12+
./examples/boltzmann_wealth_model <examples/boltzmann_wealth_model>
1313
1414
```

docs/examples/boid_flockers.md

Lines changed: 266 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,266 @@
1+
2+
## Description
3+
# Boids Flockers
4+
5+
## Summary
6+
7+
An implementation of Craig Reynolds's Boids flocker model. Agents (simulated birds) try to fly towards the average position of their neighbors and in the same direction as them, while maintaining a minimum distance. This produces flocking behavior.
8+
9+
This model tests Mesa's continuous space feature, and uses numpy arrays to represent vectors. It also demonstrates how to create custom visualization components.
10+
11+
## Installation
12+
13+
To install the dependencies use pip and the requirements.txt in this directory. e.g.
14+
15+
```
16+
$ pip install -r requirements.txt
17+
```
18+
19+
## How to Run
20+
21+
* To launch the visualization interactively, run ``mesa runserver`` in this directory. e.g.
22+
23+
```
24+
$ mesa runserver
25+
```
26+
27+
or
28+
29+
Directly run the file ``run.py`` in the terminal. e.g.
30+
31+
```
32+
$ python run.py
33+
```
34+
35+
* Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/) and press Reset, then Run.
36+
37+
## Files
38+
39+
* [model.py](model.py): Core model file; contains the Boid Model and Boid Agent class.
40+
* [app.py](app.py): Visualization code.
41+
42+
## Further Reading
43+
44+
The following link can be visited for more information on the boid flockers model:
45+
https://cs.stanford.edu/people/eroberts/courses/soco/projects/2008-09/modeling-natural-systems/boids.html
46+
47+
48+
## Agents
49+
50+
```python
51+
import numpy as np
52+
53+
from mesa import Agent
54+
55+
56+
class Boid(Agent):
57+
"""A Boid-style flocker agent.
58+
59+
The agent follows three behaviors to flock:
60+
- Cohesion: steering towards neighboring agents.
61+
- Separation: avoiding getting too close to any other agent.
62+
- Alignment: try to fly in the same direction as the neighbors.
63+
64+
Boids have a vision that defines the radius in which they look for their
65+
neighbors to flock with. Their speed (a scalar) and direction (a vector)
66+
define their movement. Separation is their desired minimum distance from
67+
any other Boid.
68+
"""
69+
70+
def __init__(
71+
self,
72+
model,
73+
speed,
74+
direction,
75+
vision,
76+
separation,
77+
cohere=0.03,
78+
separate=0.015,
79+
match=0.05,
80+
):
81+
"""Create a new Boid flocker agent.
82+
83+
Args:
84+
speed: Distance to move per step.
85+
direction: numpy vector for the Boid's direction of movement.
86+
vision: Radius to look around for nearby Boids.
87+
separation: Minimum distance to maintain from other Boids.
88+
cohere: the relative importance of matching neighbors' positions
89+
separate: the relative importance of avoiding close neighbors
90+
match: the relative importance of matching neighbors' headings
91+
"""
92+
super().__init__(model)
93+
self.speed = speed
94+
self.direction = direction
95+
self.vision = vision
96+
self.separation = separation
97+
self.cohere_factor = cohere
98+
self.separate_factor = separate
99+
self.match_factor = match
100+
self.neighbors = None
101+
102+
def step(self):
103+
"""Get the Boid's neighbors, compute the new vector, and move accordingly."""
104+
self.neighbors = self.model.space.get_neighbors(self.pos, self.vision, False)
105+
n = 0
106+
match_vector, separation_vector, cohere = np.zeros((3, 2))
107+
for neighbor in self.neighbors:
108+
n += 1
109+
heading = self.model.space.get_heading(self.pos, neighbor.pos)
110+
cohere += heading
111+
if self.model.space.get_distance(self.pos, neighbor.pos) < self.separation:
112+
separation_vector -= heading
113+
match_vector += neighbor.direction
114+
n = max(n, 1)
115+
cohere = cohere * self.cohere_factor
116+
separation_vector = separation_vector * self.separate_factor
117+
match_vector = match_vector * self.match_factor
118+
self.direction += (cohere + separation_vector + match_vector) / n
119+
self.direction /= np.linalg.norm(self.direction)
120+
new_pos = self.pos + self.direction * self.speed
121+
self.model.space.move_agent(self, new_pos)
122+
123+
```
124+
125+
126+
## Model
127+
128+
```python
129+
"""Flockers.
130+
=============================================================
131+
A Mesa implementation of Craig Reynolds's Boids flocker model.
132+
Uses numpy arrays to represent vectors.
133+
"""
134+
135+
import numpy as np
136+
137+
import mesa
138+
139+
from .agents import Boid
140+
141+
142+
class BoidFlockers(mesa.Model):
143+
"""Flocker model class. Handles agent creation, placement and scheduling."""
144+
145+
def __init__(
146+
self,
147+
seed=None,
148+
population=100,
149+
width=100,
150+
height=100,
151+
vision=10,
152+
speed=1,
153+
separation=1,
154+
cohere=0.03,
155+
separate=0.015,
156+
match=0.05,
157+
):
158+
"""Create a new Flockers model.
159+
160+
Args:
161+
population: Number of Boids
162+
width, height: Size of the space.
163+
speed: How fast should the Boids move.
164+
vision: How far around should each Boid look for its neighbors
165+
separation: What's the minimum distance each Boid will attempt to
166+
keep from any other
167+
cohere, separate, match: factors for the relative importance of
168+
the three drives.
169+
"""
170+
super().__init__(seed=seed)
171+
self.population = population
172+
self.vision = vision
173+
self.speed = speed
174+
self.separation = separation
175+
176+
self.space = mesa.space.ContinuousSpace(width, height, True)
177+
self.factors = {"cohere": cohere, "separate": separate, "match": match}
178+
self.make_agents()
179+
180+
def make_agents(self):
181+
"""Create self.population agents, with random positions and starting headings."""
182+
for _ in range(self.population):
183+
x = self.random.random() * self.space.x_max
184+
y = self.random.random() * self.space.y_max
185+
pos = np.array((x, y))
186+
direction = np.random.random(2) * 2 - 1
187+
boid = Boid(
188+
model=self,
189+
speed=self.speed,
190+
direction=direction,
191+
vision=self.vision,
192+
separation=self.separation,
193+
**self.factors,
194+
)
195+
self.space.place_agent(boid, pos)
196+
197+
def step(self):
198+
self.agents.shuffle_do("step")
199+
200+
```
201+
202+
203+
## App
204+
205+
```python
206+
from mesa.visualization import Slider, SolaraViz, make_space_matplotlib
207+
208+
from .model import BoidFlockers
209+
210+
211+
def boid_draw(agent):
212+
if not agent.neighbors: # Only for the first Frame
213+
neighbors = len(agent.model.space.get_neighbors(agent.pos, agent.vision, False))
214+
else:
215+
neighbors = len(agent.neighbors)
216+
217+
if neighbors <= 1:
218+
return {"color": "red", "size": 20}
219+
elif neighbors >= 2:
220+
return {"color": "green", "size": 20}
221+
222+
223+
model_params = {
224+
"population": Slider(
225+
label="Number of boids",
226+
value=100,
227+
min=10,
228+
max=200,
229+
step=10,
230+
),
231+
"width": 100,
232+
"height": 100,
233+
"speed": Slider(
234+
label="Speed of Boids",
235+
value=5,
236+
min=1,
237+
max=20,
238+
step=1,
239+
),
240+
"vision": Slider(
241+
label="Vision of Bird (radius)",
242+
value=10,
243+
min=1,
244+
max=50,
245+
step=1,
246+
),
247+
"separation": Slider(
248+
label="Minimum Separation",
249+
value=2,
250+
min=1,
251+
max=20,
252+
step=1,
253+
),
254+
}
255+
256+
model = BoidFlockers()
257+
258+
page = SolaraViz(
259+
model,
260+
[make_space_matplotlib(agent_portrayal=boid_draw)],
261+
model_params=model_params,
262+
name="Boid Flocking Model",
263+
)
264+
page # noqa
265+
266+
```

0 commit comments

Comments
 (0)