Skip to content

Commit 1c73a60

Browse files
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
1 parent 541dc07 commit 1c73a60

5 files changed

Lines changed: 141 additions & 138 deletions

File tree

gis/geo_pathogen/README.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,37 @@
11
# Geographic Disease Spread Model
22

33
A fast-spreading pathogen outbreak geo-model with no exposed/latency period.
4-
The model simulates how quarantine compliance rates at the population level affect outbreak dynamics in a real geo mapped environment,
4+
The model simulates how quarantine compliance rates at the population level affect outbreak dynamics in a real geo mapped environment,
55
analyzing changes in infection, death and immunity rates here the the dots represent not population directly but sets of highly populated areas.
66

77
**It showcases:**
88
- **Disease spread on a real geographic map**Disease spread using real geographic proximity(not grid cells) and agent movement is bounded within the Eurasian continent.
9-
- **Two-threshold quarantine system** - quarantine triggers when infected
10-
count exceeds an upper threshold and lifts only when it drops below a
11-
lower one, preventing quarantine from lifting the moment a single agent
12-
recovers
13-
- **Compliance rate** - a configurable fraction of citizens actually follow
9+
- **Two-threshold quarantine system** - quarantine triggers when infected
10+
count exceeds an upper threshold and lifts only when it drops below a
11+
lower one, preventing quarantine from lifting the moment a single agent
12+
recovers
13+
- **Compliance rate** - a configurable fraction of citizens actually follow
1414
quarantine orders, attempting to simulate real-world partial adherence. The rest
1515
keep moving freely by not following quarantine instructions.
1616
- **Geographic flee behavior** — compliant healthy agents moves away from quarantined zones during lockdown.
17-
- **Infected agents freeze** — simulating a government isolating/quarantining an infected
17+
- **Infected agents freeze** — simulating a government isolating/quarantining an infected
1818
zone. Non-compliant agents ignore this entirely.
1919
- **Emergence of different outcomes** — combination of different configurations produce dramatically different outbreak curves.
2020

2121
## How It Works
2222

2323
1. **Initialization** — citizens are placed randomly(more or less realistically) on a geographic map using mesa-geo. A configurable number are set initially as infected.
24-
2. **Disease Spread** — each step, healthy agents check their neighbours within a certain proximity for infected if its within the set infection radius, if there's an infection there is a configurable chance of transmission.
24+
2. **Disease Spread** — each step, healthy agents check their neighbours within a certain proximity for infected if its within the set infection radius, if there's an infection there is a configurable chance of transmission.
2525
No latency period — infection is immediate on contact,chance of getting an infection is 60%.
26-
3. **Quarantine System** — the model monitors total infected count each step.
27-
When it exceeds the upper threshold, quarantine activates. It only lifts
26+
3. **Quarantine System** — the model monitors total infected count each step.
27+
When it exceeds the upper threshold, quarantine activates. It only lifts
2828
when infected drops below the lower threshold.
2929
4. **Agent Behaviour during Quarantine:**
3030
- Compliant agents - flee away from all infected agents.
3131
- Non-compliant agents - move randomly, ignoring quarantine
3232
- Infected agents - compliant ones, freeze in place, simulating isolation or a lockdowned zone
33-
5. **Recovery** — after 10 steps of infection, agents recover to full
34-
immunity or die with the probability of 10%. Dead agents remain
33+
5. **Recovery** — after 10 steps of infection, agents recover to full
34+
immunity or die with the probability of 10%. Dead agents remain
3535
on the grid as red circles(this is an intentional mechanic) as a visual indicator to assess how compliance affects the model.
3636

3737
## Interesting Cases to Observe

gis/geo_pathogen/agents.py

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1+
import random
2+
13
import mesa_geo as mg
24
from shapely.geometry import Point
3-
import random
45

56

67
class Citizen(mg.GeoAgent):
7-
88
def __init__(self, model, geometry, crs):
99
super().__init__(model, geometry, crs)
1010

@@ -13,7 +13,6 @@ def __init__(self, model, geometry, crs):
1313
self.compliant = random.random() < self.model.compliance_rate
1414

1515
def step(self):
16-
1716
if self.model.quarantine_status and self.compliant:
1817
self.quarantine()
1918
else:
@@ -33,7 +32,9 @@ def step(self):
3332

3433
cell_state = "healthy"
3534

36-
cell_neigh = self.model.space.get_neighbors_within_distance(self, self.model.exposure)
35+
cell_neigh = self.model.space.get_neighbors_within_distance(
36+
self, self.model.exposure
37+
)
3738

3839
for i in cell_neigh:
3940
if isinstance(i, Citizen) and i.state == "infected":
@@ -45,11 +46,11 @@ def step(self):
4546
self.state = "infected"
4647

4748
def quarantine(self):
48-
4949
if self.state == "dead" or self.state == "infected":
5050
return
5151
infected = [
52-
a for a in self.model.agents
52+
a
53+
for a in self.model.agents
5354
if isinstance(a, Citizen) and a.state == "infected"
5455
]
5556
if not infected:
@@ -58,25 +59,26 @@ def quarantine(self):
5859
nearest = min(infected, key=lambda a: self.geometry.distance(a.geometry))
5960
dx = self.geometry.x - nearest.geometry.x
6061
dy = self.geometry.y - nearest.geometry.y
61-
dist = max((dx**2 + dy**2)**0.5, 1)
62+
dist = max((dx**2 + dy**2) ** 0.5, 1)
6263
scale = self.model.mobility_range / dist
63-
np = Point(
64-
self.geometry.x + dx * scale,
65-
self.geometry.y + dy * scale
66-
)
64+
np = Point(self.geometry.x + dx * scale, self.geometry.y + dy * scale)
6765
if self.model.asia_boundary.contains(np):
68-
self.geometry = np
66+
self.geometry = np
6967

7068
def move(self):
7169
if self.state != "dead":
72-
73-
change_x = self.random.randint(-self.model.mobility_range, self.model.mobility_range)
74-
change_y = self.random.randint(-self.model.mobility_range, self.model.mobility_range)
70+
change_x = self.random.randint(
71+
-self.model.mobility_range, self.model.mobility_range
72+
)
73+
change_y = self.random.randint(
74+
-self.model.mobility_range, self.model.mobility_range
75+
)
7576
np = Point(self.geometry.x + change_x, self.geometry.y + change_y)
7677
if self.model.asia_boundary.contains(np):
7778
self.geometry = np
7879

80+
7981
class CountryAgent(mg.GeoAgent):
8082
def __init__(self, model, geometry, crs):
8183
super().__init__(model, geometry, crs)
82-
self.atype = "safe"
84+
self.atype = "safe"

gis/geo_pathogen/app.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
from agents import Citizen
12
from mesa.visualization import SolaraViz, make_plot_component
23
from mesa_geo.visualization import make_geospace_component
34
from model import Geo_Model
4-
from agents import Citizen
5+
56

67
def citizen_draw(agent):
78
if not isinstance(agent, Citizen):
89
return {"color": "Gray", "fillOpacity": 0.1, "weight": 1}
9-
10+
1011
if agent.state == "healthy":
1112
return {"color": "Green", "radius": 3}
1213
elif agent.state == "infected":
@@ -16,6 +17,7 @@ def citizen_draw(agent):
1617
elif agent.state == "dead":
1718
return {"color": "Black", "radius": 3}
1819

20+
1921
model_params = {
2022
"compliance": {
2123
"type": "SliderFloat",
@@ -40,7 +42,7 @@ def citizen_draw(agent):
4042
"min": 1,
4143
"max": 20,
4244
"step": 1,
43-
}
45+
},
4446
}
4547

4648
model = Geo_Model(n=100, infn=5)

0 commit comments

Comments
 (0)