Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mesa implementation of Ising Model #138

Open
wants to merge 83 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
2925aac
created ising model
vitorfrois Jul 13, 2024
ec724b3
created ising model
vitorfrois Jul 13, 2024
ff3b7fa
final fixes
vitorfrois Jul 13, 2024
d60038e
fix portrayal
vitorfrois Jul 14, 2024
df3b9e0
categorize example models into groups
wang-boyu Jul 16, 2024
e137a60
Make batch_run pytestable by adding main() functions (#143)
EwoutH Jul 22, 2024
b5ad740
Readme: Name mesa-2.x branch for example for Mesa 2.x
EwoutH Aug 2, 2024
72cfb9e
CI: Don't test stable builds (until Mesa 3.0 is released)
EwoutH Aug 2, 2024
fe7f71e
[pre-commit.ci] pre-commit autoupdate (#149)
pre-commit-ci[bot] Aug 6, 2024
17c65ce
merge README files into top level README
wang-boyu Jul 21, 2024
68b6d31
Address duplicate position warning (#122)
rht Aug 10, 2024
352ac32
CI: Increase pytest verbosity
EwoutH Aug 10, 2024
ebb7976
CI: Let pytest generate summary report
EwoutH Aug 10, 2024
78b8a36
Use SolaraViz instead of JupyterViz in examples
EwoutH Aug 11, 2024
cc65481
sugerscape_g1mt: Refactor using AgentSet functionality
EwoutH Aug 10, 2024
923a83e
charts: Don't pass pos
EwoutH Aug 10, 2024
fbf80af
shape: Don't pass pos
EwoutH Aug 10, 2024
4dac7dc
wolf_sheep: Replace custom scheduler with AgentSet functionality
EwoutH Aug 10, 2024
487561d
bank_reserves: Don't pass pos
EwoutH Aug 10, 2024
86cdf99
CI: Let pytest treat warnings as errors
EwoutH Aug 10, 2024
3e0d16f
sugerscape_g1mt: Use model.get_agents_of_type instead of .select()
EwoutH Aug 11, 2024
274a1bc
schelling_experimental: Fix SolaraViz import
EwoutH Aug 18, 2024
bd17361
Replace model.schedule.agents with model.agents AgentSet
EwoutH Aug 17, 2024
642a9ad
Replace RandomActivation scheduler with AgentSet
EwoutH Aug 17, 2024
8e0ccf6
Replace SimultaneousActivation scheduler by AgentSet
EwoutH Aug 17, 2024
dbedf6f
Remove adding agents to schedulers
EwoutH Aug 17, 2024
4b66a64
Custom schedule replacements
EwoutH Aug 17, 2024
c0ea5a2
Restore Sugerscape and Wolf-sheep schedulers
EwoutH Aug 17, 2024
1fa7a25
Final fixes
EwoutH Aug 17, 2024
0c6366c
bank_reserves/charts: Don't make Bank an Agent
EwoutH Aug 17, 2024
0ebc4d1
Add docstring note that Bank is a regular class, not an Agent
EwoutH Aug 18, 2024
43622b9
Revert PR #161: Replace schedulers with AgentSet functionality (#170)
EwoutH Aug 22, 2024
2b944ff
Ant Colony Optimization (#157)
zjost Aug 24, 2024
2fd8945
gis: Use relative imports in all models
EwoutH Aug 25, 2024
7ecbb93
Create script to test GIS examples
EwoutH Aug 25, 2024
eed4f7d
CI: Modernize examples test script
EwoutH Aug 25, 2024
c2f4a73
CI: Add workflow to test gis models
EwoutH Aug 25, 2024
efffb67
Define optional gis dependencies in pyproject.toml
EwoutH Aug 25, 2024
49342ea
Update optional dependencies and CI
EwoutH Aug 25, 2024
4fe5c71
Add super().__init__() to Mesa model initalization (#175)
EwoutH Aug 25, 2024
bbf5ad2
Fix 3 data path imports in gis models (#176)
EwoutH Aug 25, 2024
269ff1a
Fix data paths and model passing in GIS examples (#177)
EwoutH Aug 26, 2024
3c71ea9
fixing comments
vitorfrois Aug 27, 2024
6e59b9a
Fix marker function name
vitorfrois Aug 28, 2024
1d67252
Ensure grasspatches info is only collected if gras is true (#181)
quaquel Aug 28, 2024
2bc3a2d
Update SugarscapeG1mt for automatic time advancement
EwoutH Aug 29, 2024
3e5ebd1
schelling_experimental: Remove temporary _advance_time() method (#162)
EwoutH Aug 29, 2024
2ece0cf
GoL_fast: Add fast PropertyLayer implementation of Game of Life
EwoutH Aug 29, 2024
541b004
GoL_fast: Add minimal Solara visualisation
EwoutH Aug 29, 2024
aee22c1
GoL_fast: Add metrics, datacollector and measure viz
EwoutH Aug 29, 2024
a0d50a8
GoL_fast: Add Readme
EwoutH Aug 29, 2024
875110a
Add scipy to test dependencies
EwoutH Aug 29, 2024
eb66dae
pytest: Don't raise FutureWarning to Error
EwoutH Aug 29, 2024
be57796
Readme: Add Conway's Game Of "Life" Model (Fast)
EwoutH Aug 29, 2024
fc18ece
GoL_fast: Remove advance_time()
EwoutH Aug 30, 2024
0fd7f82
Reinstate PR #161: Replace schedulers with AgentSet functionality
EwoutH Aug 30, 2024
3d29e4c
test_examples: assert model.steps == 10
EwoutH Aug 30, 2024
dee6363
gis: Use gzip.open opener in RasterLayer.from_file (#184)
EwoutH Sep 2, 2024
89f9379
gis: Pass model to RasterLayer.from_file (#186)
EwoutH Sep 2, 2024
6312ebe
add model default params for agents-networks gis example
wang-boyu Sep 2, 2024
f24626e
fix unhashable type error in agents-networks gis example
wang-boyu Sep 2, 2024
679b677
set output_dir parameter for agents-networks gis example
wang-boyu Sep 3, 2024
330b4d9
[pre-commit.ci] pre-commit autoupdate (#188)
pre-commit-ci[bot] Sep 3, 2024
aca30a2
gis: fix user warning when testing geo schelling example
wang-boyu Sep 3, 2024
e7345de
Replace `get_agents_of_type` method with `agents_by_type` property (#…
EwoutH Sep 3, 2024
831be82
Readme: Add note about Mesa-Geo version compatiblity
EwoutH Sep 3, 2024
c4b4c75
Add seeding RL examples folder (#178)
harshmahesheka Sep 4, 2024
ec07d89
aoc_tsp: Replace scheduler with AgentSet functionality (#191)
EwoutH Sep 4, 2024
660102f
Remove unique_id and model.next_id (#194)
quaquel Sep 5, 2024
d79f74e
update boltzmann-wealth update to use new solaraviz api
Corvince Sep 5, 2024
2b43544
Add visualization element explanation
Corvince Sep 5, 2024
9c30387
update examples to use new SolaraViz API (#193)
Corvince Sep 17, 2024
31537d8
GoL_fast: Make datacollection import explicit (#199)
EwoutH Sep 20, 2024
9a5396f
Use performance optimized shuffle_do() method (#201)
EwoutH Sep 21, 2024
8d0c722
Replace the remaining schedulers with AgentSet functionality (#202)
EwoutH Sep 21, 2024
ed6f910
updated file name, using only pertinent parameters
vitorfrois Sep 23, 2024
561f1f1
updating ising
vitorfrois Sep 23, 2024
ecb8aab
updating ising
vitorfrois Sep 23, 2024
44a3ed5
solara viz
vitorfrois Sep 23, 2024
7d75683
last fixes
vitorfrois Sep 23, 2024
1a01780
update var name
vitorfrois Sep 23, 2024
cd2eb61
Merge branch 'ising'
vitorfrois Sep 24, 2024
0704d13
fix tests warnings
vitorfrois Sep 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions examples/ising/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Ising Model

## Summary

The Ising model (or Lenz–Ising model), named after the physicists Ernst Ising and Wilhelm Lenz, is a mathematical model of ferromagnetism in statistical mechanics. The model consists of discrete variables that represent magnetic dipole moments of atomic "spins" that can be in one of two states (+1 or −1). The spins are arranged in a graph, usually a lattice (where the local structure repeats periodically in all directions), allowing each spin to interact with its neighbors. Neighboring spins that agree have a lower energy than those that disagree; the system tends to the lowest energy but heat disturbs this tendency, thus creating the possibility of different structural phases. The model allows the identification of phase transitions as a simplified model of reality. The two-dimensional square-lattice Ising model is one of the simplest statistical models to show a phase transition.

## How to Run

To run the model interactively, run ``solara run run.py`` in this directory. e.g.

Then open your browser to [http://127.0.0.1:8521/](http://127.0.0.1:8521/) and press ``run``.

## Things to Try

What happens when the temperature slider is very high? (This is called the "paramagnetic" state.) Try this with different **Spin Up Probability** values.

What happens when the temperature slider is set very low? (This is called the "ferromagnetic" state.) Again, try this with different **Spin Up Probability** values.

Between these two very different behaviors is a transition point. On an infinite grid, the transition point can be proved to be $2 / ln (1 + sqrt 2)$, which is about 2.27. On a large enough finite toroidal grid, the transition point is near this number.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have means of aggregating various param sweep into a single plot of magnetization vs temperature. This is a homework for us developers to allow visualizing batch_run result easily.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


## References

(NetLogo Ising)[https://ccl.northwestern.edu/netlogo/models/Ising]

(Introduction to Monte Carlo methods for an Ising Model of a Ferromagnet)[https://arxiv.org/pdf/0803.0217]
47 changes: 47 additions & 0 deletions examples/ising/ising/model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import mesa
import numpy as np

from .spin import Spin


class IsingModel(mesa.Model):
def __init__(
self,
width=50,
height=50,
spin_up_probability: float = 0.7,
temperature: float = 1,
):
super().__init__()
self.temperature = temperature
self.grid = mesa.space.SingleGrid(width, height, torus=True)

for contents, (x, y) in self.grid.coord_iter():
cell = Spin((x, y), self, Spin.DOWN)
if self.random.random() < spin_up_probability:
cell.state = cell.UP
self.grid.place_agent(cell, (x, y))

self.running = True

def step(self):
agents_list = list(self.agents)
self._steps += 1000
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand this correctly, you are using _step to count the number of agent activations (you use 1000, as in the for loop). Why use _step for this?

for i in range(1000):
random_spin = self.random.choice(agents_list)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having to create a new list of agents from scratch and selecting one is not ideal. I know this is a limitation of AgentSet. @EwoutH any idea to do this in a performant way via AgentSet? It seems to be a tower of abstractions, that it has slowed down the benchmark for mesa-frames as well: see https://github.com/adamamer20/mesa-frames/issues/25.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the comment. it does not feel right at all haha.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently I don’t think there is. @vitorfrois could you open a new issue on the main Mesa repo describing this lack of functionality and linking to this PR as example?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was going to suggest you can just do:

self.agents.select(n=1000)

But looking at our current implementation (here) that isn’t actually random.

What you can do though is:

self.agents.shuffle().select(n=1000)

dE = self.get_energy_change(random_spin)
if dE < 0:
vitorfrois marked this conversation as resolved.
Show resolved Hide resolved
random_spin.state *= -1
else:
if self.random.random() < self.boltzmann(dE):
random_spin.state *= -1

def get_energy_change(self, spin: Spin):
neighbors = spin.neighbors()
sum_over_neighbors = 0
for neighbor in neighbors:
sum_over_neighbors += neighbor.state
return sum_over_neighbors * 2 * spin.state

def boltzmann(self, dE):
vitorfrois marked this conversation as resolved.
Show resolved Hide resolved
return np.exp(-dE / self.temperature)
15 changes: 15 additions & 0 deletions examples/ising/ising/portrayal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
def portraySpin(spin):
vitorfrois marked this conversation as resolved.
Show resolved Hide resolved
"""
This function is registered with the visualization server to be called
each tick to indicate how to draw the cell in its current state.
:param cell: the cell in the simulation
:return: the portrayal dictionary.
"""
if spin is None:
raise AssertionError
return {
"marker": "s",
vitorfrois marked this conversation as resolved.
Show resolved Hide resolved
"x": spin.x,
"y": spin.y,
"color": "grey" if spin.state is spin.UP else "black",
}
19 changes: 19 additions & 0 deletions examples/ising/ising/spin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import mesa


class Spin(mesa.Agent):
"""Represents a single ALIVE or DEAD cell in the simulation."""

UP = 1
DOWN = -1

def __init__(self, pos, model, init_state):
"""
Create a cell, in the given state, at the given x, y position.
"""
super().__init__(pos, model)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn’t this map to unique_id, model?

If intended, please add a comment, if not, update

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pos is a tuple (x,y), so I think it makes more sense to name it like this instead of unique_id. I updated the name to position to be more informative

self.x, self.y = pos
self.state = init_state

def neighbors(self):
return self.model.grid.iter_neighbors((self.x, self.y), True)
vitorfrois marked this conversation as resolved.
Show resolved Hide resolved
28 changes: 28 additions & 0 deletions examples/ising/run.py
vitorfrois marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import solara
from ising.model import IsingModel
from ising.portrayal import portraySpin
from mesa.visualization import JupyterViz
vitorfrois marked this conversation as resolved.
Show resolved Hide resolved
from mesa.visualization.UserParam import Slider

model_params = {
"temperature": Slider(
label="Temperature", value=2, min=0.01, max=10, step=0.06, dtype=float
),
"spin_up_probability": Slider(
label="Spin Up Probability",
value=0.5,
min=0,
max=1,
step=0.05,
),
}


@solara.component
def Page():
JupyterViz(
vitorfrois marked this conversation as resolved.
Show resolved Hide resolved
IsingModel,
model_params,
name="Ising Model",
agent_portrayal=portraySpin,
)