How can I make it so agents only perform action during a certain time step in mesa (python)?

Question:

I’m trying to create an agent-based model using the mesa python framework. I want my agents to reproduce only on certain days of the year. Specifically, on days 203 through 209. Here is my model so far:

import mesa
import random

#set up class for agent
class Oyster(mesa.Agent):
    
    """An agent with randomly assigned initial energy & age."""
   
    #define init values
    def __init__(self, unique_id, model):
         super().__init__(unique_id, model)
         self.age = random.randint(0, 3649)
         self.energy = random.randint(1,10)

    #define what happens at each step      
    def step(self):
        living = True
        self.age += 1
        self.energy += random.randint(-5, 5)
       
        # Death
        if self.energy < 0 or self.age > 3650:
            self.model.grid.remove_agent(self)
            self.model.schedule.remove(self)
            living = False
        
        # Repoduction
        if living & self.energy >= 1.5 and self.age > 365:
            for i in range(random.randint(1,6)):
                babyOyster = Oyster(
                    self.model.next_id(), self.model, self.energy, self.age
                )
                self.model.grid.place_agent(babyOyster, self.pos)
                self.model.schedule.add(babyOyster)

    
#set up class for model
class OysterModel(mesa.Model):
    """A model with some number of agents."""

    #define init parameters
    def __init__(self, N, width, height):
        self.num_agents = N
        self.grid = mesa.space.MultiGrid(width, height, True)
        self.schedule = mesa.time.RandomActivation(self)
        self.running = True
        
        # Create agents
        for i in range(self.num_agents):
            a = Oyster(i, self)
            self.schedule.add(a)
            
            # Add the agent to a random grid cell
            x = self.random.randrange(self.grid.width)
            y = self.random.randrange(self.grid.height)
            self.grid.place_agent(a, (x, y))

    #define step
    def step(self):
        """Advance the model by one step."""
        self.schedule.step()

I feel like the code should be something like "reproduce when the step number is divisible by 203-209" but I’m very new to python so I don’t know how to get this. I also don’t know how the agent can access the step number?

Asked By: ifoxfoot

||

Answers:

So this is my current solution!

First, I added a new attribute to the Model class called step_count and I initialized it to be equal to 0. Then under the step function in the Model class, I added 1 to step-count.

In the Agent class created an if statement where reproduction only happens if step_count is divisible by my desired interval.

There was also an issue with next_id which was preventing my reproduction code from working. I would get an error saying AttributeError: 'Model' object has no attribute 'current_id'. I fixed that by setting current_id = 0 when I initialized the model. See code below:

#this tutorial uses the mesa package
import mesa
import random


#set up class for agent
class Oyster(mesa.Agent):
    
    """An agent with randomly assigned initial energy & age."""
   
    #define init values
    def __init__(self, unique_id, model, age = 0):
         super().__init__(unique_id, model)
         self.energy = random.randint(1,10)
         self.age = age

    #define what happens at each step      
    def step(self):
        living = True
        self.age += 1
        self.energy += random.randint(-5, 5)
       
        # Death
        if (self.energy < 0) or (self.age > 3650):
            self.model.grid.remove_agent(self)
            self.model.schedule.remove(self)
            living = False

        #reproduction
        if living & (self.age > 365) and (self.energy > 2) and self.model.step_count%50 == 0 : 
            for i in range(3):
                babyOyster = Oyster(
                    self.model.next_id(), self.model
                )
                x = self.random.randrange(self.model.grid.width)
                y = self.random.randrange(self.model.grid.height)
                self.model.grid.place_agent(babyOyster, (x, y))
                self.model.schedule.add(babyOyster)

    
#set up class for model
class OysterModel(mesa.Model):
    """A model with some number of agents."""

    #define init parameters
    def __init__(self, N, width, height):
        self.num_agents = N
        self.grid = mesa.space.MultiGrid(width, height, True)
        self.schedule = mesa.time.RandomActivation(self)
        self.running = True
        self.step_count = 0
        self.current_id = 0
        
        # Create agents
        for i in range(self.num_agents):
            x = self.random.randrange(self.grid.width)
            y = self.random.randrange(self.grid.height)
            age = random.randint(1, 3649)
            oyster = Oyster(self.next_id(), self, age)
            self.grid.place_agent(oyster, (x, y))
            self.schedule.add(oyster)

    #definte step
    def step(self):
        """Advance the model by one step."""
        self.schedule.step()
        self.step_count += 1

I also changed a few things to make sure baby wasn’t staying in the same cell as the parent and the baby’s age starts at 0. Hopefully this helps someone else, and if anyone finds a better solution let me know!

Answered By: ifoxfoot