Skip to content

Commit

Permalink
init gh action + poetry (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
chadsr authored Nov 21, 2021
1 parent 9779822 commit f34bb6e
Show file tree
Hide file tree
Showing 9 changed files with 1,388 additions and 109 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Tests

on:
push:
branches:
- "master"
- "main"
pull_request:

jobs:
lint:
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v2
- name: Install Python 3
uses: actions/setup-python@v2
- name: Lint
uses: ricardochaves/[email protected]
with:
use-pylint: false
use-pycodestyle: false
use-flake8: false
use-black: true
use-mypy: false
use-isort: false
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Fire Evacuation ABM

The ![accompanying paper](https://github.com/Chadsr/MesaFireEvacuation/blob/master/Influence_of_Human_Behaviour_in_the_Evacuation_of_a_Burning_Building.pdf) includes both specification and experimental results.
The [accompanying paper](./docs/Influence_of_Human_Behaviour_in_the_Evacuation_of_a_Burning_Building.pdf) includes both specification and experimental results.

## Setup
**Requires Python 3.x**
*You will need to install [Poetry](https://python-poetry.org/docs/) using your preferred method, first, then:*

```
pip install -r requirements.txt
poetry install
```

## Usage
Expand Down
238 changes: 181 additions & 57 deletions fire_evacuation/agent.py

Large diffs are not rendered by default.

96 changes: 80 additions & 16 deletions fire_evacuation/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,16 @@ class FireEvacuation(Model):
MIN_VISION = 1
# MAX_VISION is simply the size of the grid

def __init__(self, floor_plan_file, human_count, collaboration_percentage, fire_probability, visualise_vision, random_spawn, save_plots):
def __init__(
self,
floor_plan_file,
human_count,
collaboration_percentage,
fire_probability,
visualise_vision,
random_spawn,
save_plots,
):
# Load floorplan
# floorplan = np.genfromtxt(path.join("fire_evacuation/floorplans/", floor_plan_file))
with open(os.path.join("fire_evacuation/floorplans/", floor_plan_file), "rt") as f:
Expand Down Expand Up @@ -76,7 +85,9 @@ def __init__(self, floor_plan_file, human_count, collaboration_percentage, fire_
elif value is "E":
floor_object = FireExit((x, y), self)
self.fire_exit_list.append((x, y))
self.door_list.append((x, y)) # Add fire exits to doors as well, since, well, they are
self.door_list.append(
(x, y)
) # Add fire exits to doors as well, since, well, they are
elif value is "F":
floor_object = Furniture((x, y), self)
self.furniture_list.append((x, y))
Expand All @@ -97,7 +108,9 @@ def __init__(self, floor_plan_file, human_count, collaboration_percentage, fire_

# If the location is empty, or a door
if not agents or any(isinstance(agent, Door) for agent in agents):
neighbors = self.grid.get_neighborhood(pos, moore=True, include_center=True, radius=1)
neighbors = self.grid.get_neighborhood(
pos, moore=True, include_center=True, radius=1
)

for neighbor in neighbors:
# If there is contents at this location and they are not Doors or FireExits, skip them
Expand All @@ -112,12 +125,20 @@ def __init__(self, floor_plan_file, human_count, collaboration_percentage, fire_
"Alive": lambda m: self.count_human_status(m, Human.Status.ALIVE),
"Dead": lambda m: self.count_human_status(m, Human.Status.DEAD),
"Escaped": lambda m: self.count_human_status(m, Human.Status.ESCAPED),
"Incapacitated": lambda m: self.count_human_mobility(m, Human.Mobility.INCAPACITATED),
"Incapacitated": lambda m: self.count_human_mobility(
m, Human.Mobility.INCAPACITATED
),
"Normal": lambda m: self.count_human_mobility(m, Human.Mobility.NORMAL),
"Panic": lambda m: self.count_human_mobility(m, Human.Mobility.PANIC),
"Verbal Collaboration": lambda m: self.count_human_collaboration(m, Human.Action.VERBAL_SUPPORT),
"Physical Collaboration": lambda m: self.count_human_collaboration(m, Human.Action.PHYSICAL_SUPPORT),
"Morale Collaboration": lambda m: self.count_human_collaboration(m, Human.Action.MORALE_SUPPORT)
"Verbal Collaboration": lambda m: self.count_human_collaboration(
m, Human.Action.VERBAL_SUPPORT
),
"Physical Collaboration": lambda m: self.count_human_collaboration(
m, Human.Action.PHYSICAL_SUPPORT
),
"Morale Collaboration": lambda m: self.count_human_collaboration(
m, Human.Action.MORALE_SUPPORT
),
}
)

Expand All @@ -144,17 +165,52 @@ def __init__(self, floor_plan_file, human_count, collaboration_percentage, fire_

# Vision statistics obtained from http://www.who.int/blindness/GLOBALDATAFINALforweb.pdf
vision_distribution = [0.0058, 0.0365, 0.0424, 0.9153]
vision = int(np.random.choice(np.arange(self.MIN_VISION, self.width + 1, (self.width / len(vision_distribution))), p=vision_distribution))

nervousness_distribution = [0.025, 0.025, 0.1, 0.1, 0.1, 0.3, 0.2, 0.1, 0.025, 0.025] # Distribution with slight higher weighting for above median nerovusness
nervousness = int(np.random.choice(range(self.MIN_NERVOUSNESS, self.MAX_NERVOUSNESS + 1), p=nervousness_distribution)) # Random choice starting at 1 and up to and including 10
vision = int(
np.random.choice(
np.arange(
self.MIN_VISION,
self.width + 1,
(self.width / len(vision_distribution)),
),
p=vision_distribution,
)
)

nervousness_distribution = [
0.025,
0.025,
0.1,
0.1,
0.1,
0.3,
0.2,
0.1,
0.025,
0.025,
] # Distribution with slight higher weighting for above median nerovusness
nervousness = int(
np.random.choice(
range(self.MIN_NERVOUSNESS, self.MAX_NERVOUSNESS + 1),
p=nervousness_distribution,
)
) # Random choice starting at 1 and up to and including 10

experience = random.randint(self.MIN_EXPERIENCE, self.MAX_EXPERIENCE)

belief_distribution = [0.9, 0.1] # [Believes, Doesn't Believe]
believes_alarm = np.random.choice([True, False], p=belief_distribution)

human = Human(pos, health=health, speed=speed, vision=vision, collaborates=collaborates, nervousness=nervousness, experience=experience, believes_alarm=believes_alarm, model=self)
human = Human(
pos,
health=health,
speed=speed,
vision=vision,
collaborates=collaborates,
nervousness=nervousness,
experience=experience,
believes_alarm=believes_alarm,
model=self,
)

self.grid.place_agent(human, pos)
self.schedule.add(human)
Expand All @@ -173,27 +229,35 @@ def save_figures(self):
dpi = 100
fig, axes = plt.subplots(figsize=(1920 / dpi, 1080 / dpi), dpi=dpi, nrows=1, ncols=3)

status_results = results.loc[:, ['Alive', 'Dead', 'Escaped']]
status_results = results.loc[:, ["Alive", "Dead", "Escaped"]]
status_plot = status_results.plot(ax=axes[0])
status_plot.set_title("Human Status")
status_plot.set_xlabel("Simulation Step")
status_plot.set_ylabel("Count")

mobility_results = results.loc[:, ['Incapacitated', 'Normal', 'Panic']]
mobility_results = results.loc[:, ["Incapacitated", "Normal", "Panic"]]
mobility_plot = mobility_results.plot(ax=axes[1])
mobility_plot.set_title("Human Mobility")
mobility_plot.set_xlabel("Simulation Step")
mobility_plot.set_ylabel("Count")

collaboration_results = results.loc[:, ['Verbal Collaboration', 'Physical Collaboration', 'Morale Collaboration']]
collaboration_results = results.loc[
:, ["Verbal Collaboration", "Physical Collaboration", "Morale Collaboration"]
]
collaboration_plot = collaboration_results.plot(ax=axes[2])
collaboration_plot.set_title("Human Collaboration")
collaboration_plot.set_xlabel("Simulation Step")
collaboration_plot.set_ylabel("Successful Attempts")
collaboration_plot.set_ylim(ymin=0)

timestr = time.strftime("%Y%m%d-%H%M%S")
plt.suptitle("Percentage Collaborating: " + str(self.collaboration_percentage) + "%, Number of Human Agents: " + str(self.human_count), fontsize=16)
plt.suptitle(
"Percentage Collaborating: "
+ str(self.collaboration_percentage)
+ "%, Number of Human Agents: "
+ str(self.human_count),
fontsize=16,
)
plt.savefig(OUTPUT_DIR + "/model_graphs/" + timestr + ".png")
plt.close(fig)

Expand Down
68 changes: 48 additions & 20 deletions fire_evacuation/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,32 +71,60 @@ def fire_evacuation_portrayal(agent):
canvas_element = CanvasGrid(fire_evacuation_portrayal, 50, 50, 800, 800)

# Define the charts on our web interface visualisation
status_chart = ChartModule([{"Label": "Alive", "Color": "blue"},
{"Label": "Dead", "Color": "red"},
{"Label": "Escaped", "Color": "green"}])

mobility_chart = ChartModule([{"Label": "Normal", "Color": "green"},
{"Label": "Panic", "Color": "red"},
{"Label": "Incapacitated", "Color": "blue"}])

collaboration_chart = ChartModule([{"Label": "Verbal Collaboration", "Color": "orange"},
{"Label": "Physical Collaboration", "Color": "red"},
{"Label": "Morale Collaboration", "Color": "pink"}])
status_chart = ChartModule(
[
{"Label": "Alive", "Color": "blue"},
{"Label": "Dead", "Color": "red"},
{"Label": "Escaped", "Color": "green"},
]
)

mobility_chart = ChartModule(
[
{"Label": "Normal", "Color": "green"},
{"Label": "Panic", "Color": "red"},
{"Label": "Incapacitated", "Color": "blue"},
]
)

collaboration_chart = ChartModule(
[
{"Label": "Verbal Collaboration", "Color": "orange"},
{"Label": "Physical Collaboration", "Color": "red"},
{"Label": "Morale Collaboration", "Color": "pink"},
]
)

# Get list of available floorplans
floor_plans = [f for f in listdir("fire_evacuation/floorplans") if path.isfile(path.join("fire_evacuation/floorplans", f))]
floor_plans = [
f
for f in listdir("fire_evacuation/floorplans")
if path.isfile(path.join("fire_evacuation/floorplans", f))
]

# Specify the parameters changeable by the user, in the web interface
model_params = {
"floor_plan_file": UserSettableParameter("choice", "Floorplan", value=floor_plans[0], choices=floor_plans),
"floor_plan_file": UserSettableParameter(
"choice", "Floorplan", value=floor_plans[0], choices=floor_plans
),
"human_count": UserSettableParameter("number", "Number Of Human Agents", value=10),
"collaboration_percentage": UserSettableParameter("slider", "Percentage Collaborating", value=50, min_value=0, max_value=100, step=10),
"fire_probability": UserSettableParameter("slider", "Probability of Fire", value=0.1, min_value=0, max_value=1, step=0.01),
"random_spawn": UserSettableParameter('checkbox', 'Spawn Agents at Random Locations', value=True),
"visualise_vision": UserSettableParameter('checkbox', 'Show Agent Vision', value=False),
"save_plots": UserSettableParameter('checkbox', 'Save plots to file', value=True)
"collaboration_percentage": UserSettableParameter(
"slider", "Percentage Collaborating", value=50, min_value=0, max_value=100, step=10
),
"fire_probability": UserSettableParameter(
"slider", "Probability of Fire", value=0.1, min_value=0, max_value=1, step=0.01
),
"random_spawn": UserSettableParameter(
"checkbox", "Spawn Agents at Random Locations", value=True
),
"visualise_vision": UserSettableParameter("checkbox", "Show Agent Vision", value=False),
"save_plots": UserSettableParameter("checkbox", "Save plots to file", value=True),
}

# Start the visual server with the model
server = ModularServer(FireEvacuation, [canvas_element, status_chart, mobility_chart, collaboration_chart], "Fire Evacuation",
model_params)
server = ModularServer(
FireEvacuation,
[canvas_element, status_chart, mobility_chart, collaboration_chart],
"Fire Evacuation",
model_params,
)
Loading

0 comments on commit f34bb6e

Please sign in to comment.