-
Notifications
You must be signed in to change notification settings - Fork 1k
Description
Describe the bug
When using a PropertyLayer class with DataCollector, the data is not captured properly at each model step. Specifically, for each model step, the grid of values for the PropertyLayer instance are stored only as they appear in the final model step, i.e. all steps store the same array of values.
Expected behavior
The DataCollector should store at each step the value of the PropertyLayer at that step as a model variable. This would allow visualization of the distribution of the variable at each step of the model to examine, for example, the accumulation of pollution in the Sugarscape model.
To Reproduce
The toy model below reproduces the issue. Check the 'Pollution' column of the model_results object to see the problem. Minimally, one would expect a grid of 0's for the first model step, which is not the case here either.
import mesa
class testAgent(mesa.Agent):
def __init__(self, unique_id, model, pos):
super().__init__(unique_id, model)
self.pos = pos
def pollute(self):
self.model.grid.properties["pollution"].modify_cell(self.pos, lambda p: p+1)
class testModel(mesa.Model):
def __init__(self, width = 20, height = 20, initial_population=200):
super().__init__()
self.width = width
self.height = height
self.initial_population = initial_population
# initiate activation schedule
self.schedule = mesa.time.RandomActivationByType(self) #activate different type of agents in different order each time
# initiate mesa grid class
self.grid = mesa.space.MultiGrid(self.width, self.height, torus=False)
#add pollution property layer
pollution_layer = mesa.space.PropertyLayer(name = "pollution", width = self.width, height = self.height, default_value = 0)
self.grid.add_property_layer(pollution_layer)
self.datacollector = mesa.DataCollector(model_reporters = {"Pollution": lambda m: m.grid.properties["pollution"].data})
agent_id = 0
for i in range(self.initial_population):
# get agent position
x = self.random.randrange(self.width)
y = self.random.randrange(self.height)
agent = testAgent(agent_id, self, (x, y))
# place agent
self.grid.place_agent(agent, (x, y))
self.schedule.add(agent)
agent_id += 1
def randomizeAgents(self):
agents_shuffle = list(self.schedule.agents_by_type[testAgent].values())
self.random.shuffle(agents_shuffle)
return agents_shuffle
def step(self):
agents_shuffle = self.randomizeAgents()
for agent in agents_shuffle:
agent.pollute()
self.datacollector.collect(self)
def run_model(self, step_count=20):
for i in range(step_count):
self.step()
model = testModel()
model.run_model()
model_results = model.datacollector.get_model_vars_dataframe()
Additional context
This should be running on the most recent version of Mesa (my version was updated about a week ago).