Spatial and Netlogo like Models¶
ABCE deliberately does not provide spatial representation, instead it integrates with other packages that specialize in spatial representation.
Netlogo like models¶
For Netlogo like models in Python, we recommend using ABCE together with MESA
A simple example shows how to build a spatial model in ABCE using MESA:
A wrapper file to start the graphical representation and the simulation¶
""" This is a simple demonstration model how to integrate ABCE and mesa.
The model and scheduler specification are taken care of in
ABCE instead of Mesa.
Based on
https://github.com/projectmesa/mesa/tree/master/examples/boltzmann_wealth_model.
For further reading, see
[Dragulescu, A and Yakovenko, V. Statistical Mechanics of Money, Income, and Wealth: A Short Survey. November, 2002](http://arxiv.org/pdf/cond-mat/0211175v1.pdf)
"""
from model import MoneyModel
from mesa.visualization.modules import CanvasGrid
from mesa.visualization.ModularVisualization import ModularServer
from mesa.visualization.modules import ChartModule
def agent_portrayal(agent):
""" This function returns a big red circle, when an agent is wealthy and a
small gray circle when he is not """
portrayal = {"Shape": "circle",
"Filled": "true",
"r": 0.5}
if agent.report_wealth() > 0:
portrayal["Color"] = "red"
portrayal["Layer"] = 0
else:
portrayal["Color"] = "grey"
portrayal["Layer"] = 1
portrayal["r"] = 0.2
return portrayal
def main(x_size, y_size):
""" This function sets up a canvas to graphically represent the model 'MoneyModel'
and a chart, than it runs the server and runs the model in model.py in the browser """
grid = CanvasGrid(agent_portrayal, x_size, y_size, 500, 500)
chart = ChartModule([{"Label": "Gini",
"Color": "Black"}],
data_collector_name='datacollector')
# the simulation uses a class DataCollector, that collects the data and
# relays it from self.datacollector to the webpage
server = ModularServer(MoneyModel,
[grid, chart],
"ABCE and MESA integrated",
x_size * y_size, x_size, y_size)
server.port = 8534 # change this number if address is in use
server.launch()
if __name__ == '__main__':
main(25, 25)
A file with the simulation itself, that can be executed also without the GUI¶
""" This is a simple demonstration model how to integrate ABCE and mesa.
The model and scheduler specification are taken care of in
ABCE instead of Mesa.
Based on
https://github.com/projectmesa/mesa/tree/master/examples/boltzmann_wealth_model.
For further reading, see
[Dragulescu, A and Yakovenko, V. Statistical Mechanics of Money, Income, and Wealth: A Short Survey. November, 2002](http://arxiv.org/pdf/cond-mat/0211175v1.pdf)
"""
import abce
from mesa.space import MultiGrid
from mesa.datacollection import DataCollector
from moneyagent import MoneyAgent
def compute_gini(model):
""" calculates the index of wealth distribution form a list of numbers """
agent_wealths = model.wealths
x = sorted(agent_wealths)
N = len(agent_wealths)
B = sum(xi * (N - i) for i, xi in enumerate(x)) / (N * sum(x))
return 1 + (1 / N) - 2 * B
class MoneyModel(abce.Simulation): # The actual simulation must inherit from Simulation
""" The actual simulation. In order to interoperate with MESA the simulation
needs to be encapsulated in a class. __init__ sets the simulation up. The step
function runs one round of the simulation. """
def __init__(self, num_agents, x_size, y_size):
abce.Simulation.__init__(self,
name='ABCE and MESA integrated',
rounds=300,
processes=1)
# initialization of the base class. MESA integration requires
# single processing
self.grid = MultiGrid(x_size, y_size, True)
self.agents = self.build_agents(MoneyAgent, 'MoneyAgent', num_agents,
parameters={'grid': self.grid})
# ABCE agents must inherit the MESA grid
self.running = True
# MESA requires this
self.datacollector = DataCollector(
model_reporters={"Gini": compute_gini})
# The data collector collects a certain aggregate value so the graphical
# components can access them
self.wealths = [0 for _ in range(num_agents)]
def step(self):
""" In every step the agent's methods are executed, every set the round
counter needs to be increased by self.next_round() """
self.next_round()
self.agents.do('move')
self.agents.do('give_money')
self.wealths = self.agents.do('report_wealth')
# agents report there wealth in a list self.wealth
self.datacollector.collect(self)
# collects the data
if __name__ == '__main__':
""" If you run model.py the simulation is executed without graphical
representation """
money_model = MoneyModel(1000, 20, 50)
for r in range(100):
print(r)
money_model.step()
A simple agent¶
import abce
import random
class MoneyAgent(abce.Agent):
""" agents move randomly on a grid and give_money to another agent in the same cell """
def init(self, parameters, agent_parameters):
self.grid = parameters["grid"]
""" the grid on which agents live must be imported """
x = random.randrange(self.grid.width)
y = random.randrange(self.grid.height)
self.pos = (x, y)
self.grid.place_agent(self, (x, y))
self.create('money', random.randrange(2, 10))
def move(self):
""" moves randomly """
possible_steps = self.grid.get_neighborhood(self.pos,
moore=True,
include_center=False)
new_position = random.choice(possible_steps)
self.grid.move_agent(self, new_position)
def give_money(self):
""" If the agent has wealth he gives it to cellmates """
cellmates = self.grid.get_cell_list_contents([self.pos])
if len(cellmates) > 1:
other = random.choice(cellmates)
try:
self.give(other.group, other.id, good='money', quantity=1)
except abce.NotEnoughGoods:
pass
def report_wealth(self):
return self.possession('money')