Skip to content

Adds a fast-spreading pathogen model with quarantine and compliance#359

Open
Syn-Eon wants to merge 9 commits intomesa:mainfrom
Syn-Eon:pathogen-outbreak
Open

Adds a fast-spreading pathogen model with quarantine and compliance#359
Syn-Eon wants to merge 9 commits intomesa:mainfrom
Syn-Eon:pathogen-outbreak

Conversation

@Syn-Eon
Copy link

@Syn-Eon Syn-Eon commented Mar 5, 2026

Pathogen Outbreak and Quarantine Compliance Model

Adds a fast-spreading pathogen model with automatic
quarantine and with it compliance rate mechanics.

Resolves #356

Mesa features used

  • MultiGrid, DataCollector, SolaraViz
  • make_space_component, make_plot_component
  • graphical mapping per step with a quarantine indicator
  • with the latest mesa 3.5 code structure

Mesa version

4

How to run

pip install -r requirements.txt
solara run app.py

@jackiekazil @EwoutH

Demo of no compliance model

no_compliance

@Syn-Eon Syn-Eon force-pushed the pathogen-outbreak branch 2 times, most recently from fd41d91 to 9191f55 Compare March 6, 2026 05:01
@Syn-Eon Syn-Eon changed the title Adds a fast-spreading pathogen model with quarantine and compliance m… Adds a fast-spreading pathogen model with quarantine and compliance Mar 6, 2026
@EwoutH
Copy link
Member

EwoutH commented Mar 15, 2026

Thanks for the PR, looks like an interesting model.

Could you:

  • Fix the test failure (a rebase might be enough)
  • Request a peer-review (and maybe do one or two yourself)

@Syn-Eon Syn-Eon force-pushed the pathogen-outbreak branch from 6b1d69a to d1c1a79 Compare March 17, 2026 06:12
@Syn-Eon Syn-Eon force-pushed the pathogen-outbreak branch from eb3e620 to 8276b8b Compare March 18, 2026 04:35
@abhinavk0220
Copy link

abhinavk0220 commented Mar 19, 2026

Peer Review — Pathogen Outbreak & Quarantine Compliance Model

Reviewed agents.py, model.py, app.py, and README.md in full.


Overall

The two-threshold quarantine hysteresis is a genuinely interesting mechanic most epidemic examples use a single threshold and get oscillating quarantine on/off behaviour. The compliance + flee behaviour is well thought out and the four-screenshot README is one of the clearest I've seen for demonstrating parameter sensitivity. A few correctness issues before merge.


Critical: Non-seeded RNG throughout agents.py

import random
...
self.compliant = random.random() < self.model.compliance_rate
if random.random() > 0.40:
    self.state = "infected"
chance_of_death = random.random()

Every stochastic decision uses Python's global random module instead of self.random (Mesa's seeded RNG). This makes the model completely non-reproducible — running with rng=42 twice will give different results. Replace all random.random() calls with self.random.random().


Missing package structure

agents.py and model.py live directly in examples/pathogen_outbreak/ with no subdirectory package. All other examples in this repo use a pattern like examples/my_model/my_model/agents.py. app.py then does from model import PathogenModel (a relative import that only works when app.py is run from its own directory). This should be from pathogen_outbreak.model import PathogenModel with a proper pathogen_outbreak/__init__.py.


DataCollector.collect not called at __init__

model.py calls self.datacollector.collect(self) as the first thing in step(), but never in __init__. This means the time-series chart starts at step 1 with no step-0 baseline. Adding self.datacollector.collect(self) at the end of __init__ is standard Mesa practice and gives a clean starting point.


O(n) infected-position scan inside every compliant agent's quarantine()

for i in self.model.agents:
    if i.state == "infected":
        infected_pos.append(i.cell.coordinate)

Every compliant healthy agent scans all agents to find infected positions each step. With 300 agents during quarantine, this is O(n²) per step. A simple fix: cache infected_positions as a model-level attribute computed once at the start of step(), then reuse it in each agent call.


README says MultiGrid, code uses OrthogonalMooreGrid

citizens are placed randomly on a MultiGrid

The model uses OrthogonalMooreGrid (Mesa 4.x API), not MultiGrid (removed in Mesa 4.x). Update the README to match the actual implementation.


Dead agents block movement

Dead agents remain on the grid (intentional, per README) but since is_empty returns False for cells they occupy, they silently block other agents from moving to those cells. This affects the flee and random-move logic. It's worth noting this in the README so the user understands why high-death scenarios can produce movement deadlocks.


quarantine chart in graph_ot

graph_ot = make_plot_component(["healthy", "infected", "immune", "dead", "quarantine"])

quarantine is a model reporter (returns 0 or 1), not an agent reporter. make_plot_component with a list uses model reporters, so this is fine but it would be clearer to explicitly pass a dict with labels and colors rather than a plain list.


Summary

The model concept is strong and the README is excellent. The two things that need fixing before merge: (1) replace all random.random() with self.random.random() for reproducibility, and (2) restructure into a proper package directory. Everything else is advisory.

Syn-Eon pushed a commit to Syn-Eon/mesa-examples that referenced this pull request Mar 19, 2026
@Syn-Eon Syn-Eon force-pushed the pathogen-outbreak branch from 26d8520 to f100519 Compare March 20, 2026 11:07
@Syn-Eon
Copy link
Author

Syn-Eon commented Mar 20, 2026

Peer Review — Pathogen Outbreak & Quarantine Compliance Model

Reviewed agents.py, model.py, app.py, and README.md in full.

Overall

The two-threshold quarantine hysteresis is a genuinely interesting mechanic most epidemic examples use a single threshold and get oscillating quarantine on/off behaviour. The compliance + flee behaviour is well thought out and the four-screenshot README is one of the clearest I've seen for demonstrating parameter sensitivity. A few correctness issues before merge.

Critical: Non-seeded RNG throughout agents.py

import random
...
self.compliant = random.random() < self.model.compliance_rate
if random.random() > 0.40:
    self.state = "infected"
chance_of_death = random.random()

Every stochastic decision uses Python's global random module instead of self.random (Mesa's seeded RNG). This makes the model completely non-reproducible — running with rng=42 twice will give different results. Replace all random.random() calls with self.random.random().

Missing package structure

agents.py and model.py live directly in examples/pathogen_outbreak/ with no subdirectory package. All other examples in this repo use a pattern like examples/my_model/my_model/agents.py. app.py then does from model import PathogenModel (a relative import that only works when app.py is run from its own directory). This should be from pathogen_outbreak.model import PathogenModel with a proper pathogen_outbreak/__init__.py.

DataCollector.collect not called at __init__

model.py calls self.datacollector.collect(self) as the first thing in step(), but never in __init__. This means the time-series chart starts at step 1 with no step-0 baseline. Adding self.datacollector.collect(self) at the end of __init__ is standard Mesa practice and gives a clean starting point.

O(n) infected-position scan inside every compliant agent's quarantine()

for i in self.model.agents:
    if i.state == "infected":
        infected_pos.append(i.cell.coordinate)

Every compliant healthy agent scans all agents to find infected positions each step. With 300 agents during quarantine, this is O(n²) per step. A simple fix: cache infected_positions as a model-level attribute computed once at the start of step(), then reuse it in each agent call.

README says MultiGrid, code uses OrthogonalMooreGrid

citizens are placed randomly on a MultiGrid

The model uses OrthogonalMooreGrid (Mesa 4.x API), not MultiGrid (removed in Mesa 4.x). Update the README to match the actual implementation.

Dead agents block movement

Dead agents remain on the grid (intentional, per README) but since is_empty returns False for cells they occupy, they silently block other agents from moving to those cells. This affects the flee and random-move logic. It's worth noting this in the README so the user understands why high-death scenarios can produce movement deadlocks.

quarantine chart in graph_ot

graph_ot = make_plot_component(["healthy", "infected", "immune", "dead", "quarantine"])

quarantine is a model reporter (returns 0 or 1), not an agent reporter. make_plot_component with a list uses model reporters, so this is fine but it would be clearer to explicitly pass a dict with labels and colors rather than a plain list.

Summary

The model concept is strong and the README is excellent. The two things that need fixing before merge: (1) replace all random.random() with self.random.random() for reproducibility, and (2) restructure into a proper package directory. Everything else is advisory.

Thanks for the review, really appreciate it. I fixed the two critical issues i.e I restructured the files into a proper package directory and used mesas own random function for proper seeding. Also added a note about dead agents blocking movement to the README file. Once again thanks for the review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add: Fast-Spreading Pathogen Model with Quarantine Compliance Mechanics

3 participants