Example #1
1
class ForestFire(Model):
    '''
    Simple Forest Fire model.
    '''
    def __init__(self, height, width, density):
        '''
        Create a new forest fire model.

        Args:
            height, width: The size of the grid to model
            density: What fraction of grid cells have a tree in them.
        '''
        # Initialize model parameters
        self.height = height
        self.width = width
        self.density = density

        # Set up model objects
        self.schedule = RandomActivation(self)
        self.grid = Grid(height, width, torus=False)

        self.datacollector = DataCollector(
            {"Fine": lambda m: self.count_type(m, "Fine"),
             "On Fire": lambda m: self.count_type(m, "On Fire"),
             "Burned Out": lambda m: self.count_type(m, "Burned Out")})

        # Place a tree in each cell with Prob = density
        for (contents, x, y) in self.grid.coord_iter():
            if random.random() < self.density:
                # Create a tree
                new_tree = TreeCell((x, y))
                # Set all trees in the first column on fire.
                if x == 0:
                    new_tree.condition = "On Fire"
                self.grid._place_agent((x, y), new_tree)
                self.schedule.add(new_tree)
        self.running = True

    def step(self):
        '''
        Advance the model by one step.
        '''
        self.schedule.step()
        self.datacollector.collect(self)

        # Halt if no more fire
        if self.count_type(self, "On Fire") == 0:
            self.running = False

    @staticmethod
    def count_type(model, tree_condition):
        '''
        Helper method to count trees in a given condition in a given model.
        '''
        count = 0
        for tree in model.schedule.agents:
            if tree.condition == tree_condition:
                count += 1
        return count
Example #2
0
class WorldModel(Model):
    def __init__(self, N, width, height):
        self.grid = SingleGrid(height, width, True)

        self.schedule = RandomActivation(self)
        self.num_agents = N
        self.running = True
        
        for i in range(self.num_agents):
            ethnicity = random.choice(Ethnicities)
            a = PersonAgent(unique_id=i,
                            model=self,
                            ethnicity=int(ethnicity)
                            )
            self.schedule.add(a)
            # Add the agent to a random grid cell

            self.grid.position_agent(a)
            
        self.datacollector = DataCollector(
            agent_reporters={
                "Nationalism": lambda a: a.nationalism,
                "X": lambda a: a.pos[0],
                "Y": lambda a: a.pos[1]
            }
        )

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()
Example #3
0
class BoltzmannWealthModelNetwork(Model):
    """A model with some number of agents."""

    def __init__(self, num_agents=7, num_nodes=10):

        self.num_agents = num_agents
        self.num_nodes = num_nodes if num_nodes >= self.num_agents else self.num_agents
        self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=0.5)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.datacollector = DataCollector(
            model_reporters={"Gini": compute_gini},
            agent_reporters={"Wealth": lambda _: _.wealth}
        )

        list_of_random_nodes = self.random.sample(self.G.nodes(), self.num_agents)

        # Create agents
        for i in range(self.num_agents):
            a = MoneyAgent(i, self)
            self.schedule.add(a)
            # Add the agent to a random node
            self.grid.place_agent(a, list_of_random_nodes[i])

        self.running = True
        self.datacollector.collect(self)

    def step(self):
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

    def run_model(self, n):
        for i in range(n):
            self.step()
Example #4
0
class MoneyModel(Model):
    """A model with some number of agents."""
    def __init__(self, N, width, height):
        self.num_agents = N
        self.running = True
        self.grid = MultiGrid(height, width, True)
        self.schedule = RandomActivation(self)
        self.datacollector = DataCollector(model_reporters={"Gini": compute_gini},
                agent_reporters={"Wealth": lambda a: a.wealth})
        # Create agents
        for i in range(self.num_agents):
            a = MoneyAgent(i)
            self.schedule.add(a)
            # Add the agent to a random grid cell
            x = random.randrange(self.grid.width)
            y = random.randrange(self.grid.height)
            self.grid.place_agent(a, (x, y))

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()
    
    def run_model(self, n):
        for i in range(n):
            self.step()
class Money_Model(Model):
    def __init__(self, N, width=50, height=50, torus=True):
        self.num_agents = N
        self.schedule = RandomActivation(self)
        self.grid = MultiGrid(height, width, torus)
        self.create_agents()
        self.dc = DataCollector({"Gini": lambda m: m.compute_gini()},
                               {"Wealth": lambda a: a.wealth})
        self.running = True

    def create_agents(self):
        for i in range(self.num_agents):
            a = Money_Agent(i)
            self.schedule.add(a)
            x = random.randrange(self.grid.width)
            y = random.randrange(self.grid.height)
            self.grid.place_agent(a, (x, y))

    def step(self):
        self.dc.collect(self)
        self.schedule.step()
        
    def run_model(self, steps):
        for i in range(steps):
            self.step()
    
    def compute_gini(self):
        agent_wealths = [agent.wealth for agent in self.schedule.agents]
        x = sorted(agent_wealths)
        N = self.num_agents
        B = sum( xi * (N-i) for i,xi in enumerate(x) ) / (N*sum(x))
        return (1 + (1/N) - 2*B)
Example #6
0
File: model.py Project: GeoESW/mesa
class MoneyModel(Model):
    """A simple model of an economy where agents exchange currency at random.

    All the agents begin with one unit of currency, and each time step can give
    a unit of currency to another agent. Note how, over time, this produces a
    highly skewed distribution of wealth.
    """

    def __init__(self, N, width, height):
        self.num_agents = N
        self.running = True
        self.grid = MultiGrid(height, width, True)
        self.schedule = RandomActivation(self)
        self.datacollector = DataCollector(
            model_reporters={"Gini": compute_gini},
            agent_reporters={"Wealth": lambda a: a.wealth}
        )
        # Create agents
        for i in range(self.num_agents):
            a = MoneyAgent(i, self)
            self.schedule.add(a)
            # Add the agent to a random grid cell
            x = random.randrange(self.grid.width)
            y = random.randrange(self.grid.height)
            self.grid.place_agent(a, (x, y))

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()

    def run_model(self, n):
        for i in range(n):
            self.step()
Example #7
0
class SchellingModel(Model):
    '''
    Model class for the Schelling segregation model.
    '''

    def __init__(self, height, width, density, minority_pc, homophily):
        '''
        '''

        self.height = height
        self.width = width
        self.density = density
        self.minority_pc = minority_pc
        self.homophily = homophily

        self.schedule = RandomActivation(self)
        self.grid = Grid(height, width, torus=True)

        self.happy = 0
        self.datacollector = DataCollector(
            {"happy": lambda m: m.happy}, # Model-level count of happy agents
            # For testing purposes, agent's individual x and y
            {"x": lambda a: a.x, "y": lambda a: a.y}) 

        self.running = True

        # Set up agents
        for x in range(self.width):
            for y in range(self.height):
                if random.random() < self.density:
                    if random.random() < self.minority_pc:
                        agent_type = 1
                    else:
                        agent_type = 0

                    agent = SchellingAgent((x,y), x, y, agent_type)
                    self.grid[y][x] = agent
                    self.schedule.add(agent)

    def get_empty(self):
        '''
        Get a list of coordinate tuples of currently-empty cells.
        '''
        empty_cells = []
        for x in range(self.width):
            for y in range(self.height):
                if self.grid[y][x] is None:
                    empty_cells.append((x, y))
        return empty_cells

    def step(self):
        '''
        Run one step of the model. If All agents are happy, halt the model.
        '''
        self.happy = 0 # Reset counter of happy agents
        self.schedule.step()
        self.datacollector.collect(self)

        if self.happy == self.schedule.get_agent_count():
            self.running = False
Example #8
0
class Charts(Model):

    # grid height
    grid_h = 20
    # grid width
    grid_w = 20

    """init parameters "init_people", "rich_threshold", and "reserve_percent"
       are all UserSettableParameters"""
    def __init__(self, height=grid_h, width=grid_w, init_people=2, rich_threshold=10,
                 reserve_percent=50,):
        self.height = height
        self.width = width
        self.init_people = init_people
        self.schedule = RandomActivation(self)
        self.grid = MultiGrid(self.width, self.height, torus=True)
        # rich_threshold is the amount of savings a person needs to be considered "rich"
        self.rich_threshold = rich_threshold
        self.reserve_percent = reserve_percent
        # see datacollector functions above
        self.datacollector = DataCollector(model_reporters={
                                           "Rich": get_num_rich_agents,
                                           "Poor": get_num_poor_agents,
                                           "Middle Class": get_num_mid_agents,
                                           "Savings": get_total_savings,
                                           "Wallets": get_total_wallets,
                                           "Money": get_total_money,
                                           "Loans": get_total_loans},
                                           agent_reporters={
                                           "Wealth": lambda x: x.wealth})

        # create a single bank for the model
        self.bank = Bank(1, self, self.reserve_percent)

        # create people for the model according to number of people set by user
        for i in range(self.init_people):
            # set x, y coords randomly within the grid
            x = self.random.randrange(self.width)
            y = self.random.randrange(self.height)
            p = Person(i, (x, y), self, True, self.bank, self.rich_threshold)
            # place the Person object on the grid at coordinates (x, y)
            self.grid.place_agent(p, (x, y))
            # add the Person object to the model schedule
            self.schedule.add(p)

        self.running = True
        self.datacollector.collect(self)

    def step(self):
        # tell all the agents in the model to run their step function
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

    def run_model(self):
        for i in range(self.run_time):
            self.step()
Example #9
0
class Foraging(Model):
    
    number_of_bean = 0
    number_of_corn = 0
    number_of_soy = 0
    
    def __init__(self, width=50, height=50, torus=True, num_bug=50, seed=42, strategy=None):
        super().__init__(seed=seed)
        self.number_of_bug = num_bug
        if not(strategy in ["stick", "switch"]):
            raise TypeError("'strategy' must be one of {stick, switch}")
        self.strategy = strategy
        
        self.grid = SingleGrid(width, height, torus)
        self.schedule = RandomActivation(self)
        data = {"Bean": lambda m: m.number_of_bean,
                "Corn": lambda m: m.number_of_corn,
                "Soy": lambda m: m.number_of_soy,
                "Bug": lambda m: m.number_of_bug,
                }
        self.datacollector = DataCollector(data)
        
        # create foods
        self._populate(Bean)
        self._populate(Corn)
        self._populate(Soy)
        
        # create bugs
        for i in range(self.number_of_bug):
            pos = self.grid.find_empty()
            bug = Bug(i, self)
            bug.strategy = self.strategy
            self.grid.place_agent(bug, pos)
            self.schedule.add(bug)
    
    def step(self):
        self.schedule.step()
        self.datacollector.collect(self)
        
        if not(self.grid.exists_empty_cells()):
            self.running = False
    
    def _populate(self, food_type):
        prefix = "number_of_{}"
        
        counter = 0
        while counter < food_type.density * (self.grid.width * self.grid.height):
            pos = self.grid.find_empty()
            food = food_type(counter, self)
            self.grid.place_agent(food, pos)
            self.schedule.add(food)
            food_name = food_type.__name__.lower()
            attr_name = prefix.format(food_name)
            val = getattr(self, attr_name)
            val += 1
            setattr(self, attr_name, val)
            counter += 1
Example #10
0
class Schelling(Model):
    '''
    Model class for the Schelling segregation model.
    '''

    def __init__(self, height=20, width=20, density=0.8, minority_pc=0.2, homophily=3):
        '''
        '''

        self.height = height
        self.width = width
        self.density = density
        self.minority_pc = minority_pc
        self.homophily = homophily

        self.schedule = RandomActivation(self)
        self.grid = SingleGrid(height, width, torus=True)

        self.happy = 0
        self.datacollector = DataCollector(
            {"happy": "happy"},  # Model-level count of happy agents
            # For testing purposes, agent's individual x and y
            {"x": lambda a: a.pos[0], "y": lambda a: a.pos[1]})

        # Set up agents
        # We use a grid iterator that returns
        # the coordinates of a cell as well as
        # its contents. (coord_iter)
        for cell in self.grid.coord_iter():
            x = cell[1]
            y = cell[2]
            if self.random.random() < self.density:
                if self.random.random() < self.minority_pc:
                    agent_type = 1
                else:
                    agent_type = 0

                agent = SchellingAgent((x, y), self, agent_type)
                self.grid.position_agent(agent, (x, y))
                self.schedule.add(agent)

        self.running = True
        self.datacollector.collect(self)

    def step(self):
        '''
        Run one step of the model. If All agents are happy, halt the model.
        '''
        self.happy = 0  # Reset counter of happy agents
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

        if self.happy == self.schedule.get_agent_count():
            self.running = False
Example #11
0
class SchellingModel(Model):
    """
    Model class for the Schelling segregation model.
    """

    def __init__(self, height, width, density, minority_pc, homophily):
        """
        """

        self.height = height
        self.width = width
        self.density = density
        self.minority_pc = minority_pc
        self.homophily = homophily

        self.schedule = RandomActivation(self)
        self.grid = SingleGrid(height, width, torus=True)

        self.happy = 0
        self.total_agents = 0
        self.datacollector = DataCollector(
            {"unhappy": lambda m: m.total_agents - m.happy},
            # For testing purposes, agent's individual x and y
            {"x": lambda a: a.pos[X], "y": lambda a: a.pos[Y]},
        )

        self.running = True

        # Set up agents
        # We use a grid iterator that returns
        # the coordinates of a cell as well as
        # its contents. (coord_iter)
        for cell, x, y in self.grid.coord_iter():
            if random.random() < self.density:
                if random.random() < self.minority_pc:
                    agent_type = 1
                else:
                    agent_type = 0

                agent = SchellingAgent(self.total_agents, agent_type)
                self.grid.position_agent(agent, x, y)
                self.schedule.add(agent)
                self.total_agents += 1

    def step(self):
        """
        Run one step of the model. If All agents are happy, halt the model.
        """
        self.happy = 0  # Reset counter of happy agents
        self.schedule.step()
        self.datacollector.collect(self)

        if self.happy == self.total_agents:
            self.running = False
Example #12
0
class PD_Model(Model):
    '''
    Model class for iterated, spatial prisoner's dilemma model.
    '''

    schedule_types = {"Sequential": BaseScheduler,
                      "Random": RandomActivation,
                      "Simultaneous": SimultaneousActivation}

    # This dictionary holds the payoff for this agent,
    # keyed on: (my_move, other_move)

    payoff = {("C", "C"): 1,
              ("C", "D"): 0,
              ("D", "C"): 1.6,
              ("D", "D"): 0}

    def __init__(self, height, width, schedule_type, payoffs=None):
        '''
        Create a new Spatial Prisoners' Dilemma Model.

        Args:
            height, width: Grid size. There will be one agent per grid cell.
            schedule_type: Can be "Sequential", "Random", or "Simultaneous".
                           Determines the agent activation regime.
            payoffs: (optional) Dictionary of (move, neighbor_move) payoffs.
        '''
        self.running = True
        self.grid = SingleGrid(height, width, torus=True)
        self.schedule_type = schedule_type
        self.schedule = self.schedule_types[self.schedule_type](self)

        # Create agents
        for x in range(width):
            for y in range(height):
                agent = PD_Agent((x, y), self)
                self.grid.place_agent(agent, (x, y))
                self.schedule.add(agent)

        self.datacollector = DataCollector({
            "Cooperating_Agents":
            lambda m: len([a for a in m.schedule.agents if a.move == "C"])
        })

    def step(self):
        self.datacollector.collect(self)
        self.schedule.step()

    def run(self, n):
        '''
        Run the model for a certain number of steps.
        '''
        for _ in range(n):
            self.step()
class InspectionModel(Model):
    '''
    Simple Restaurant Inspection model.
    '''
    def __init__(self, height, width, density):
        '''
        Create a new restaurant inspection model.

        Args:
            height, width: The size of the grid to model
            density: What fraction of grid cells have a restaurant in them.
        '''
        # Initialize model parameters
        self.height = height
        self.width = width
        self.density = density

        # Set up model objects
        self.schedule = RandomActivation(self)
        self.grid = Grid(height, width, torus=False)

        self.datacollector = DataCollector(
            {"Good": lambda m: self.count_type(m, "Good"),
             "Bad": lambda m: self.count_type(m, "Bad")})

        # Place a restaurant in each cell with Prob = density
        for (contents, x, y) in self.grid.coord_iter():
            if random.random() < self.density:
                # Create a restaurant
                new_restaurant = RestaurantCell((x, y))
                self.grid._place_agent((x, y), new_restaurant)
                self.schedule.add(new_restaurant)
        self.running = True

    def step(self):
        '''
        Advance the model by one step.
        '''
        self.schedule.step()
        self.datacollector.collect(self)

    @staticmethod
    def count_type(model, restaurant_hygiene):
        '''
        Helper method to count restaurants in a given condition in a given model.
        '''
        count = 0
        for restaurant in model.schedule.agents:
            if restaurant.hygiene == restaurant_hygiene and restaurant.rating != 'Closed':
                count += 1
        return count
Example #14
0
class VirusOnNetwork(Model):
    """A virus model with some number of agents"""

    def __init__(self, num_nodes=10, avg_node_degree=3, initial_outbreak_size=1, virus_spread_chance=0.4,
                virus_check_frequency=0.4, recovery_chance=0.3, gain_resistance_chance=0.5):

        self.num_nodes = num_nodes
        prob = avg_node_degree / self.num_nodes
        self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=prob)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.initial_outbreak_size = initial_outbreak_size if initial_outbreak_size <= num_nodes else num_nodes
        self.virus_spread_chance = virus_spread_chance
        self.virus_check_frequency = virus_check_frequency
        self.recovery_chance = recovery_chance
        self.gain_resistance_chance = gain_resistance_chance

        self.datacollector = DataCollector({"Infected": number_infected,
                                            "Susceptible": number_susceptible,
                                            "Resistant": number_resistant})

        # Create agents
        for i, node in enumerate(self.G.nodes()):
            a = VirusAgent(i, self, State.SUSCEPTIBLE, self.virus_spread_chance, self.virus_check_frequency,
                           self.recovery_chance, self.gain_resistance_chance)
            self.schedule.add(a)
            # Add the agent to the node
            self.grid.place_agent(a, node)

        # Infect some nodes
        infected_nodes = self.random.sample(self.G.nodes(), self.initial_outbreak_size)
        for a in self.grid.get_cell_list_contents(infected_nodes):
            a.state = State.INFECTED

        self.running = True
        self.datacollector.collect(self)

    def resistant_susceptible_ratio(self):
        try:
            return number_state(self, State.RESISTANT) / number_state(self, State.SUSCEPTIBLE)
        except ZeroDivisionError:
            return math.inf

    def step(self):
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

    def run_model(self, n):
        for i in range(n):
            self.step()
Example #15
0
class SchellingModel(Model):
    '''
    Model class for the Schelling segregation model.
    '''

    def __init__(self, height, width, density, type_pcs=[.2, .2, .2, .2, .2]):
        '''
        '''

        self.height = height
        self.width = width
        self.density = density
        self.type_pcs = type_pcs

        self.schedule = RandomActivation(self)
        self.grid = SingleGrid(height, width, torus=False)

        self.happy = 0
        self.datacollector = DataCollector(
            {"happy": lambda m: m.happy},  # Model-level count of happy agents
            # For testing purposes, agent's individual x and y
            {"x": lambda a: a.pos[0], "y": lambda a: a.pos[1]})

        self.running = True

        # Set up agents
        # We use a grid iterator that returns
        # the coordinates of a cell as well as
        # its contents. (coord_iter)

        total_agents = self.height * self.width * self.density
        agents_by_type = [total_agents*val for val in self.type_pcs]

        for loc, types in enumerate(agents_by_type):
            for i in range(int(types)):
                pos = self.grid.find_empty()
                agent = SchellingAgent(pos, self, loc)
                self.grid.position_agent(agent, pos)
                self.schedule.add(agent)

    def step(self):
        '''
        Run one step of the model. If All agents are happy, halt the model.
        '''
        self.happy = 0  # Reset counter of happy agents
        self.schedule.step()
        self.datacollector.collect(self)

        if self.happy == self.schedule.get_agent_count():
            self.running = False
Example #16
0
    def __init__(self, num_nodes=10, avg_node_degree=3, initial_outbreak_size=1, virus_spread_chance=0.4,
                virus_check_frequency=0.4, recovery_chance=0.3, gain_resistance_chance=0.5):

        self.num_nodes = num_nodes
        prob = avg_node_degree / self.num_nodes
        self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=prob)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.initial_outbreak_size = initial_outbreak_size if initial_outbreak_size <= num_nodes else num_nodes
        self.virus_spread_chance = virus_spread_chance
        self.virus_check_frequency = virus_check_frequency
        self.recovery_chance = recovery_chance
        self.gain_resistance_chance = gain_resistance_chance

        self.datacollector = DataCollector({"Infected": number_infected,
                                            "Susceptible": number_susceptible,
                                            "Resistant": number_resistant})

        # Create agents
        for i, node in enumerate(self.G.nodes()):
            a = VirusAgent(i, self, State.SUSCEPTIBLE, self.virus_spread_chance, self.virus_check_frequency,
                           self.recovery_chance, self.gain_resistance_chance)
            self.schedule.add(a)
            # Add the agent to the node
            self.grid.place_agent(a, node)

        # Infect some nodes
        infected_nodes = self.random.sample(self.G.nodes(), self.initial_outbreak_size)
        for a in self.grid.get_cell_list_contents(infected_nodes):
            a.state = State.INFECTED

        self.running = True
        self.datacollector.collect(self)
Example #17
0
 def __init__(self, width=50, height=50, torus=True, num_bug=50, seed=42, strategy=None):
     super().__init__(seed=seed)
     self.number_of_bug = num_bug
     if not(strategy in ["stick", "switch"]):
         raise TypeError("'strategy' must be one of {stick, switch}")
     self.strategy = strategy
     
     self.grid = SingleGrid(width, height, torus)
     self.schedule = RandomActivation(self)
     data = {"Bean": lambda m: m.number_of_bean,
             "Corn": lambda m: m.number_of_corn,
             "Soy": lambda m: m.number_of_soy,
             "Bug": lambda m: m.number_of_bug,
             }
     self.datacollector = DataCollector(data)
     
     # create foods
     self._populate(Bean)
     self._populate(Corn)
     self._populate(Soy)
     
     # create bugs
     for i in range(self.number_of_bug):
         pos = self.grid.find_empty()
         bug = Bug(i, self)
         bug.strategy = self.strategy
         self.grid.place_agent(bug, pos)
         self.schedule.add(bug)
Example #18
0
    def __init__(self, height, width, schedule_type, payoffs=None):
        """
        Create a new Spatial Prisoners' Dilemma Model.

        Args:
            height, width: Grid size. There will be one agent per grid cell.
            schedule_type: Can be "Sequential", "Random", or "Simultaneous".
                           Determines the agent activation regime.
            payoffs: (optional) Dictionary of (move, neighbor_move) payoffs.
        """
        self.running = True
        self.grid = SingleGrid(height, width, torus=True)
        self.schedule_type = schedule_type
        self.schedule = self.schedule_types[self.schedule_type](self)

        # Create agents
        for x in range(width):
            for y in range(height):
                agent = PD_Agent((x, y))
                self.grid.place_agent(agent, (x, y))
                self.schedule.add(agent)

        self.datacollector = DataCollector(
            {"Cooperating_Agents": lambda m: len([a for a in m.schedule.agents if a.move == "C"])}
        )
Example #19
0
    def __init__(self, g=None, outbreak_size=3, si_trans=0.025):
        self.schedule = SimultaneousActivation(self)
        
        if g is None:
            g = nx.random_graphs.watts_strogatz_graph(100, 4, 0.05) 

        self.si_trans = si_trans

        nodes = g.nodes()
        agent_nodes = list(map(lambda x: SI_Agent(x), nodes))
        n_map = dict(zip(nodes, agent_nodes))
        agent_edges = list(map(lambda e: (n_map[e[0]], n_map[e[1]])  , g.edges()))

        for agent in agent_nodes:
            self.schedule.add(agent)
        # set the initial outbreak
        for node in sample(list(agent_nodes), outbreak_size):
            node.state = State.infected

        self.network = NetworkSpace(agent_nodes, agent_edges)
        self.dc = DataCollector({"susceptible": lambda m: self.count_state(m, State.susceptible),
                                "infected": lambda m: self.count_state(m, State.infected)},
                                {"state": lambda a: a.state.value}
                                )
        self.dc.collect(self) #initial state

        self.running = True
    def __init__(self, agent_class, agent_count, agent_args={}, seed=None):
        '''
        Instantiate a new CrisisWorld model.

        Args:
            agent_class: Class to instantiate the agents 
            agent_count: How many agents to instantiate with.
            agent_args: Dictionary of arguments to pass to all agents.
            seed: Random seed to launch the model with.
        '''
        self.agent_class = agent_class
        self.agent_count = agent_count
        self.agent_args = agent_args
        super().__init__(self.model_class, agents_per_model=2, seed=seed)
        
        # Instantiate data collector
        self.dc = DataCollector(tables={
                    "Interactions": 
                        ["Step", "A", "B", "Outcome", "SPE", "quality"],
                    "Agents": ["Name", "Assets", "Capability", "Bloc"] })

        for agent in self.agents:
            row = {"Name": agent.name, 
                   "Assets": agent.assets,
                   "Capability": agent.mil_strength,
                   "Bloc": agent.bloc}
            self.dc.add_table_row("Agents", row)
Example #21
0
    def __init__(self, height, width, density, minority_pc, homophily):
        '''
        '''

        self.height = height
        self.width = width
        self.density = density
        self.minority_pc = minority_pc
        self.homophily = homophily

        self.schedule = RandomActivation(self)
        self.grid = Grid(height, width, torus=True)

        self.happy = 0
        self.datacollector = DataCollector(
            {"happy": lambda m: m.happy}, # Model-level count of happy agents
            # For testing purposes, agent's individual x and y
            {"x": lambda a: a.x, "y": lambda a: a.y}) 

        self.running = True

        # Set up agents
        for x in range(self.width):
            for y in range(self.height):
                if random.random() < self.density:
                    if random.random() < self.minority_pc:
                        agent_type = 1
                    else:
                        agent_type = 0

                    agent = SchellingAgent((x,y), x, y, agent_type)
                    self.grid[y][x] = agent
                    self.schedule.add(agent)
    def __init__(self, height, width, density):
        '''
        Create a new restaurant inspection model.

        Args:
            height, width: The size of the grid to model
            density: What fraction of grid cells have a restaurant in them.
        '''
        # Initialize model parameters
        self.height = height
        self.width = width
        self.density = density

        # Set up model objects
        self.schedule = RandomActivation(self)
        self.grid = Grid(height, width, torus=False)

        self.datacollector = DataCollector(
            {"Good": lambda m: self.count_type(m, "Good"),
             "Bad": lambda m: self.count_type(m, "Bad")})

        # Place a restaurant in each cell with Prob = density
        for (contents, x, y) in self.grid.coord_iter():
            if random.random() < self.density:
                # Create a restaurant
                new_restaurant = RestaurantCell((x, y))
                self.grid._place_agent((x, y), new_restaurant)
                self.schedule.add(new_restaurant)
        self.running = True
Example #23
0
    def __init__(self, height, width, density):
        '''
        Create a new forest fire model.

        Args:
            height, width: The size of the grid to model
            density: What fraction of grid cells have a tree in them.
        '''
        # Initialize model parameters
        self.height = height
        self.width = width
        self.density = density

        # Set up model objects
        self.schedule = RandomActivation(self)
        self.grid = Grid(height, width, torus=False)

        self.datacollector = DataCollector(
            {"Fine": lambda m: self.count_type(m, "Fine"),
             "On Fire": lambda m: self.count_type(m, "On Fire"),
             "Burned Out": lambda m: self.count_type(m, "Burned Out")})

        # Place a tree in each cell with Prob = density
        for (contents, x, y) in self.grid.coord_iter():
            if random.random() < self.density:
                # Create a tree
                new_tree = TreeCell((x, y))
                # Set all trees in the first column on fire.
                if x == 0:
                    new_tree.condition = "On Fire"
                self.grid._place_agent((x, y), new_tree)
                self.schedule.add(new_tree)
        self.running = True
 def __init__(self, N, width=50, height=50, torus=True):
     self.num_agents = N
     self.schedule = RandomActivation(self)
     self.grid = MultiGrid(height, width, torus)
     self.create_agents()
     self.dc = DataCollector({"Gini": lambda m: m.compute_gini()},
                            {"Wealth": lambda a: a.wealth})
     self.running = True
Example #25
0
class SIR_Network_Model(Model):
    def __init__(self, g=None, outbreak_size=3, si_trans=0.025, ir_trans=0.05):
        self.schedule = SimultaneousActivation(self)
        
        if g is None:
            g = nx.random_graphs.watts_strogatz_graph(100, 4, 0.05) 

        self.si_trans = si_trans
        self.ir_trans = ir_trans

        nodes = g.nodes()
        agent_nodes = list(map(lambda x: SIR_Agent(x), nodes))
        n_map = dict(zip(nodes, agent_nodes))
        agent_edges = list(map(lambda e: (n_map[e[0]], n_map[e[1]])  , g.edges()))

        for agent in agent_nodes:
            self.schedule.add(agent)
        # set the initial outbreak
        for node in sample(list(agent_nodes), outbreak_size):
            node.state = State.infected

        self.network = NetworkSpace(agent_nodes, agent_edges)
        self.dc = DataCollector({"susceptible": lambda m: self.count_state(m, State.susceptible),
                                "infected": lambda m: self.count_state(m, State.infected),
                                "resistant": lambda m: self.count_state(m, State.resistant)},
                                {"state": lambda a: a.state.value}
                                )
        self.dc.collect(self) #initial state

        self.running = True

    def step(self):
        self.schedule.step()
        self.dc.collect(self)

        # disease dead?
        if self.count_state(self, State.infected) == 0:
            self.running = False

    @staticmethod
    def count_state(model,state):
        count = 0
        for agent in model.schedule.agents:
            if agent.state == state:
                count +=1
        return count
 def __init__(self, height, width, citizen_density, cop_density,
              citizen_vision, cop_vision, legitimacy,
              max_jail_term, active_threshold=.1, arrest_prob_constant=2.3,
              movement=True, max_iters=1000):
     super(CivilViolenceModel, self).__init__()
     self.height = height
     self.width = width
     self.citizen_density = citizen_density
     self.cop_density = cop_density
     self.citizen_vision = citizen_vision
     self.cop_vision = cop_vision
     self.legitimacy = legitimacy
     self.max_jail_term = max_jail_term
     self.active_threshold = active_threshold
     self.arrest_prob_constant = arrest_prob_constant
     self.movement = movement
     self.running = True
     self.max_iters = max_iters
     self.iteration = 0
     self.schedule = RandomActivation(self)
     self.grid = Grid(height, width, torus=True)
     model_reporters = {
         "Quiescent": lambda m: self.count_type_citizens(m, "Quiescent"),
         "Active": lambda m: self.count_type_citizens(m, "Active"),
         "Jailed": lambda m: self.count_jailed(m)}
     agent_reporters = {
         "x": lambda a: a.pos[0],
         "y": lambda a: a.pos[1],
         'breed': lambda a: a.breed,
         "jail_sentence": lambda a: getattr(a, 'jail_sentence', None),
         "condition": lambda a: getattr(a, "condition", None),
         "arrest_probability": lambda a: getattr(a, "arrest_probability",
                                                 None)
     }
     self.dc = DataCollector(model_reporters=model_reporters,
                             agent_reporters=agent_reporters)
     unique_id = 0
     if self.cop_density + self.citizen_density > 1:
         raise ValueError(
             'Cop density + citizen density must be less than 1')
     for (contents, x, y) in self.grid.coord_iter():
         if random.random() < self.cop_density:
             cop = Cop(unique_id, (x, y), vision=self.cop_vision,
                       model=self)
             unique_id += 1
             self.grid[y][x] = cop
             self.schedule.add(cop)
         elif random.random() < (
                 self.cop_density + self.citizen_density):
             citizen = Citizen(unique_id, (x, y),
                               hardship=random.random(),
                               regime_legitimacy=self.legitimacy,
                               risk_aversion=random.random(),
                               threshold=self.active_threshold,
                               vision=self.citizen_vision, model=self)
             unique_id += 1
             self.grid[y][x] = citizen
             self.schedule.add(citizen)
 def __init__(self, N):
     self.running = True
     self.num_agents = N
     self.schedule = RandomActivation(self)
     self.create_agents()
     agent_reporters = {"Wealth": lambda a: a.wealth}
     model_reporters = {"Gini": compute_gini}
     self.dc = DataCollector(model_reporters=model_reporters,
                             agent_reporters=agent_reporters)
Example #28
0
 def __init__(self):
     self.schedule = BaseScheduler(self)
     for i in range(10):
         a = MockAgent(i, i)
         self.schedule.add(a)
     self.datacollector = DataCollector(
         {"total_agents": lambda m: m.schedule.get_agent_count()},
         {"value": lambda a: a.val},
         {"Final_Values": ["agent_id", "final_value"]})
Example #29
0
class MockModel(Model):
    '''
    Minimalistic model for testing purposes.
    '''

    schedule = BaseScheduler(None)

    def __init__(self):
        self.schedule = BaseScheduler(self)
        for i in range(10):
            a = MockAgent(i, i)
            self.schedule.add(a)
        self.datacollector = DataCollector(
            {"total_agents": lambda m: m.schedule.get_agent_count()},
            {"value": lambda a: a.val},
            {"Final_Values": ["agent_id", "final_value"]})

    def step(self):
        self.schedule.step()
        self.datacollector.collect(self)
Example #30
0
    def __init__(self):
        self.schedule = BaseScheduler(self)
        self.model_val = 100

        for i in range(10):
            a = MockAgent(i, self, val=i)
            self.schedule.add(a)
        self.datacollector = DataCollector(
            {"total_agents": lambda m: m.schedule.get_agent_count(),
             "model_value": "model_val"},
            {"value": lambda a: a.val, "value2": "val2"},
            {"Final_Values": ["agent_id", "final_value"]})
Example #31
0
class AlternativeModel(Model):
    def __init__(
        self,
        n=50,
        j=5,
        m=30,
        p_1=0.1,
        p_2=0.9,
        p_3=0.9,
        q_h1=0.1,
        q_h2=0.1,
        q_ml=0.5,
        alpha=10,
        p_turb=0.1,
        q_ml_scaling="off",
    ):
        # reset random seeds prior to each iteration
        np.random.seed()
        random.seed()
        # save configuration
        self.conf = {
            "n": n,
            "j": j,
            "m": m,
            "p_1": p_1,
            "p_2": p_2,
            "p_3": p_3,
            "q_h1": q_h1,
            "q_h2": q_h2,
            "q_ml": q_ml,
            "q_ml_basic": q_ml,
            "alpha_ml": alpha,
            "p_turb": p_turb,
            "q_ml_scaling": q_ml_scaling,
        }
        self.running = True
        self.schedule = BaseScheduler(self)
        # init environment and data collector
        self.init_env()
        self.init_dc()

    def get_config(self, param, *args):
        return self.conf[param]

    # necessary in order to satisfy data collector interface
    get_m = partialmethod(get_config, "m")
    get_n = partialmethod(get_config, "n")
    get_j = partialmethod(get_config, "j")
    get_p_1 = partialmethod(get_config, "p_1")
    get_p_2 = partialmethod(get_config, "p_2")
    get_p_3 = partialmethod(get_config, "p_3")
    get_q_h1 = partialmethod(get_config, "q_h1")
    get_q_h2 = partialmethod(get_config, "q_h2")
    get_q_ml = partialmethod(get_config, "q_ml")
    get_q_ml_basic = partialmethod(get_config, "q_ml_basic")
    get_alpha_ml = partialmethod(get_config, "alpha_ml")
    get_p_turb = partialmethod(get_config, "p_turb")
    get_q_ml_scaling = partialmethod(get_config, "q_ml_scaling")

    def get_time(self, *args):
        return int(self.schedule.time)

    def init_env(self):
        # init reality
        r = Reality("R1", self)
        self.schedule.add(r)
        # init humans
        for i in range(self.conf["n"]):
            h = Human(f"H{i+1}", self)
            self.schedule.add(h)
        # init ML agents
        # determine ML dimensions
        self.conf["ml_dims"] = random_dims(self.conf["m"], self.conf["j"])
        # init one agent per dimension
        for i in self.conf["ml_dims"]:
            m = MLAgent(f"ML{i+1}", self, i)
            self.schedule.add(m)
        # init organization
        o = OrganizationalCode("O1", self)
        self.schedule.add(o)
        return

    def init_dc(self):
        # data collector enables tracking of metric at each time step
        self.datacollector = DataCollector(
            model_reporters={
                "time": self.get_time,
                "m": self.get_m,
                "n": self.get_n,
                "j": self.get_j,
                "p_1": self.get_p_1,
                "p_2": self.get_p_2,
                "p_3": self.get_p_3,
                "q_h1": self.get_q_h1,
                "q_h2": self.get_q_h2,
                "q_ml": self.get_q_ml_basic,
                "alpha_ml": self.get_alpha_ml,
                "p_turb": self.get_p_turb,
                "q_ml_scaling": self.get_q_ml_scaling,
                "avg_q_ml": calc_avg_q_ml,
                "code_kl": calc_code_kl,
                "human_kl": calc_human_kl,
                "human_kl_var": calc_kl_var,
                "human_kl_dissim": calc_dissim,
            })
        # collect metrics for time step 0
        self.datacollector.collect(self)
        return

    def get_exp_grp(self):
        # get list of humans with higher KL than code
        humans = self.get_human_agents()
        code = self.get_org_code()
        return list(filter(lambda h: (h.kl > code.kl), humans))

    def get_ml(self, dim):
        # loop through MLs to find the one with suitable dimension
        mls = self.get_ml_agents()
        ml = None
        for m in mls:
            if m.state["dim"] == dim:
                ml = m
                break
        return ml

    def get_reality(self):
        return self.schedule.agents[0]

    def get_org_code(self):
        return self.schedule.agents[-1]

    def get_human_agents(self):
        return self.schedule.agents[1:(1 + self.conf["n"])]

    def get_ml_agents(self):
        return self.schedule.agents[(1 + self.conf["n"]):-1]

    def update_kls(self):
        for h in self.get_human_agents():
            h.update_kl()
        for ml in self.get_ml_agents():
            ml.update_kl()
        code = self.get_org_code()
        code.update_kl()
        return

    def scale_q_ml(self):
        # for avg. human knowledge related manipulation
        scaling = self.conf["q_ml_scaling"]
        if scaling == "on":
            # for belief related manipulation
            humans = self.get_human_agents()
            ml_dims = self.conf["ml_dims"]
            q_ml = []
            for dim in ml_dims:
                # get knowledgeable group
                humans_dim = list(filter(lambda h: (h.state[dim] != 0),
                                         humans))
                # get basic parameters
                reality = self.get_reality().state[dim]
                q_ml_basic = self.conf["q_ml_basic"]

                if len(humans_dim) > 0:
                    # if knowledgeable group exists, count correct and incorrect beliefs
                    votes = [h.state[dim] for h in humans_dim]
                    c = Counter(votes)

                    if len(c) > 1:
                        # if knowledgeable group has correct and incorrect beliefs calculate difference
                        k = c.get(reality) - c.get((-1) * reality)
                    else:
                        if votes[0] == reality:
                            # all human beliefs are correct
                            k = c.get(reality)
                        else:
                            # all human beliefs are incorrect
                            k = c.get((-1) * reality)
                    # scale q_ml parameter according to sigmoid function
                    alpha = self.conf["alpha_ml"]
                    beta = math.log((1 - q_ml_basic) / q_ml_basic)
                    q_ml.append(
                        round(1 / (1 + math.e**(((-1) * k / alpha) + beta)),
                              3))
                else:
                    # if there are no knowledgeable humans, use basic q_ml value
                    q_ml.append(q_ml_basic)
            self.conf["q_ml"] = q_ml
        return

    def environmental_turbulence(self):
        reality = self.get_reality()
        reality.turbulence()
        return

    def step(self):
        try:
            # calculate knowledge levels
            self.update_kls()
            # determine expert group for this time step
            self.exp_grp = self.get_exp_grp()
            # scale q_ml according to human KL
            self.scale_q_ml()
            # update all agents
            self.schedule.step()
            # update reality according to turbulence
            self.environmental_turbulence()
            # collect metrics for this time step
            self.datacollector.collect(self)
        except Exception as e:
            # log potential erros, but continue with next iteration
            print("The following error occurred:")
            print(e)
            print("Model configuration:")
            print(self.conf)
Example #32
0
    def __init__(self,
                 supply,
                 demand,
                 s_strategy,
                 b_strategy,
                 highest_ask=100,
                 lowest_ask=0):
        self.supply = supply
        self.demand = demand
        self.num_sellers = supply.num_agents
        self.num_buyers = demand.num_agents
        self.initialize_spread()
        self.market_price = None
        self.history = Order_history()
        self.num_traded = 0
        self.num_step = 0
        # history records an order as a bid or ask only if it updates
        # the spread

        self.num_period = 1
        self.loc_period = [0]  # where each period happens

        # Sometimes trade does not happen within a period,
        # so we need variables to indicate them.
        self.no_trade = False

        # When a shift happens, I need to know it so that
        # I can calculate efficiency properly.
        self.shifted = False
        self.shifted_period = -1
        self.new_supply = None
        self.new_demand = None

        # How agents are activated at each step
        self.schedule = RandomChoiceActivation(self)
        # Create agents
        for i, cost in enumerate(self.supply.price_schedule):
            self.schedule.add(
                b_strategy(i, self, "seller", cost, supply.q_per_agent,
                           highest_ask, lowest_ask))
        for i, value in enumerate(self.demand.price_schedule):
            j = self.num_sellers + i
            self.schedule.add(
                s_strategy(j, self, "buyer", value, demand.q_per_agent,
                           highest_ask, lowest_ask))

        # Collecting data
        # self.datacollector = DataCollector(
        #     model_reporters={"Period": "num_period",
        #                      "OB": "outstanding_bid",
        #                      "OBer": get_bidder_id,
        #                      "OA": "outstanding_ask",
        #                      "OAer": get_asker_id,
        #                      "MarketPrice": "market_price",
        #                      "Traded": "traded",
        #                      "Order": lambda x: x.history.get_last_action(),
        #                      "Efficiency": compute_efficiency},
        #     agent_reporters={"Period": lambda x: x.model.num_period,
        #                      "Type": lambda x: type(x),
        #                      "Role": "role",
        #                      "Value": "value",
        #                      "Good": "good",
        #                      "Right": "right",
        #                      "Surplus": "surplus"}
        # )
        self.datacollector = DataCollector(model_reporters={
            "Step": "num_step",
            "Period": "num_period",
            "TransNum": "num_traded",
            "OB": "outstanding_bid",
            "OA": "outstanding_ask",
            "MarketPrice": "market_price",
            "Traded": "traded",
            "CumulativeActualSurplus": compute_actual_surplus,
            "TheoreticalSurplus": compute_theoretical_surplus,
            "CumulativeTS": compute_acc_theoretical_surplus,
            "Efficiency": compute_efficiency
        },
                                           agent_reporters={
                                               "Period":
                                               lambda x: x.model.num_period,
                                               "Type": lambda x: type(x),
                                               "Role": "role",
                                               "Value": "value",
                                               "Good": "good",
                                               "Right": "right",
                                               "Surplus": "surplus"
                                           })
class HITLAdopt(Model):

    #modify init method to accout for new parameters and constants
    def __init__(self, height, width, density, wms, wts, wus, td, ve, ae):

        # Initialize model parameters
        self.height = height
        self.width = width
        self.density = density
        self.weeklyCampaignSpend = wms
        self.weeklyTrainingSpend = wts
        self.weeklyUsabilitySpend = wus

        #initialize HITL related parameters
        self.trainingDataWeeklyInput = td
        self.vizEffect = ve

        self.learningRate = 0
        self.dataInstances = 10000
        self.algoAccuracy = ae

        self.algoEffect = self.algoAccuracy *0.1


        # Set up model objects

        #this sets the activation order of the agents (when they make their moves) to be random each step
        self.schedule = RandomActivation(self)

        #this creates the physical grid we are using to simulate word of mouth spread of the model
        self.grid = Grid(height, width, torus=False)

        #these use the Mesa DataCollector method to create several trackers to collect data from the model run
        self.dc_output = DataCollector(model_reporters={"Avg Output Value Per Person Per Week": compute_avg_output})
        self.dc_tracker = DataCollector(model_reporters={"Average IA": compute_avg_ia})
        self.dc_adoption = DataCollector({"Potential Trialer": lambda m: self.count_type(m, "Potential Trialer"),
                                "Trialer": lambda m: self.count_type(m, "Trialer"),
                                "Adopter": lambda m: self.count_type(m, "Adopter"), "Defector": lambda m: self.count_type(m, "Defector"), "Evangelist": lambda m: self.count_type(m, "Evangelist")})
        self.dc_trialers =DataCollector({"Trialer": lambda m: self.count_type(m, "Trialer")})
        self.dc_algo = DataCollector({"Learning Rate": compute_learning_rate})

        self.dc_master=DataCollector({"Potential Trialer": lambda m: self.count_type(m, "Potential Trialer"),
                                "Trialer": lambda m: self.count_type(m, "Trialer"),
                                "Adopter": lambda m: self.count_type(m, "Adopter"),
                                "Defector": lambda m: self.count_type(m, "Defector"),
                                "Evangelist": lambda m: self.count_type(m, "Evangelist"),
                                "Avg Output Value Per Person": compute_avg_output,
                                "Total Differential in Population": hitl_adv_differential,
                                "Algo Accuracy": compute_algo_accuracy,
                                "Algo Accuracy Increase": compute_learning_rate,
                                "Total Dataset Size": compute_data_instances,
                                "Algorithm Effect": compute_algo_effect,
                                "Avg Data Collection Ouput": compute_avg_dc,
                                "Avg Data Interpretation/Analysis Output": compute_avg_di,
                                "Avg Interpreting Actions Output": compute_avg_ia,
                                "Avg Coaching Output": compute_avg_coaching,
                                "Avg Review Output": compute_avg_review})

        #the logic for the creation of the agents, as well as setting the initial values of the agent parameters
        for x in range(self.width):
                for y in range(self.height):
                    if random.random() < self.density:
                        new_consultant = Consultant(self, (x, y), np.random.normal(60, 10), np.random.normal(70, 10), 0)
                        if y == 0:
                            new_consultant.condition = "Trialer"
                        self.grid[y][x] = new_consultant
                        self.schedule.add(new_consultant)

        #run the model when the class is called
        self.running = True




    #define logic of what happens with each time step model-wide
    def step(self):
        ##update algorithm accuracy, data instances, and effect for new weekly data input
        self.learningRate = 10000/self.dataInstances/13 - ((self.count_type(self, "Trialer") +
                                                           self.count_type(self, "Adopter") +
                                                           self.count_type(self, "Evangelist"))/2000000)
        self.algoAccuracy += self.learningRate
        self.dataInstances += self.trainingDataWeeklyInput
        self.algoEffect = self.algoAccuracy * 0.1
        #logic for adoption from marketing, For every 1000 of additional weekly marketing spend, we get 1 new trialer consultant each week
        for i in range (1,(int(self.weeklyCampaignSpend/100))):
            prospect = random.choice(self.schedule.agents)
            #change that agent's state to the next one up
            if prospect.condition == "Potential Trialer":
                prospect.condition = "Trialer"
            if prospect.condition == "Trialer":
                prospect.condition = "Adopter"
       #an abandoned idea for trial abandonment...I instead decided to model this at an agent level in that class (See above)
        '''for i in range (1,(int(self.weeklyMarketingSpend/50))):
            #take a random agent that's a trialer and log their x y location
            prospect = random.choice(model.schedule.agents)
            #change that agent's state to the next one up depending on what it is
            random_num = np.random.randint(1,100)
            if prospect.condition == "Trialer":
                if (prospect.techFluencyScore <70):
                    if random_num > 50:
                        prospect.condition = "PotentialTrialer"
        '''
        #sets the step count
        self.schedule.step()
        #logs appropriate data in each of the data collectors
        self.dc_output.collect(self)
        self.dc_adoption.collect(self)
        self.dc_tracker.collect(self)
        self.dc_algo.collect(self)
        self.dc_trialers.collect(self)
        self.dc_master.collect(self)
        #abandoned logic for stopping model - it was originally when there were no more trialers, now we just give it a set number of steps
    #method for counting the agents and their conditions so we can track adoption methods
    @staticmethod
    def count_type(model, consultant_condition):
        count = 0
        for consultant in model.schedule.agents:
            if consultant.condition == consultant_condition:
                count += 1
        return count
Example #34
0
class EpsteinCivilViolence(Model):
    """
    Model 1 from "Modeling civil violence: An agent-based computational
    approach," by Joshua Epstein
    http://www.pnas.org/content/99/suppl_3/7243.full
    Attributes:
        height: grid height
        width: grid width
        citizen_density: approximate % of cells occupied by citizens.
        cop_density: approximate % of calles occupied by cops.
        citizen_vision: number of cells in each direction (N, S, E and W) that
            citizen can inspect
        cop_vision: number of cells in each direction (N, S, E and W) that cop
            can inspect
        legitimacy:  (L) citizens' perception of regime legitimacy, equal
            across all citizens
        max_jail_term: (J_max)
        active_threshold: if (grievance - (risk_aversion * arrest_probability))
            > threshold, citizen rebels
        arrest_prob_constant: set to ensure agents make plausible arrest
            probability estimates
        movement: binary, whether agents try to move at step end
        max_iters: model may not have a natural stopping point, so we set a
            max.

    """
    def __init__(
        self,
        height=40,
        width=40,
        citizen_density=0.7,
        cop_density=0.074,
        citizen_vision=7,
        cop_vision=7,
        legitimacy=0.8,
        max_jail_term=1000,
        active_threshold=0.1,
        arrest_prob_constant=2.3,
        movement=True,
        initial_unemployment_rate=0.1,
        corruption_level=0.1,
        susceptible_level=0.3,
        honest_level=0.6,
        max_iters=1000,
    ):

        super().__init__()
        self.height = height
        self.width = width
        self.citizen_density = citizen_density
        self.cop_density = cop_density
        self.citizen_vision = citizen_vision
        self.cop_vision = cop_vision
        self.legitimacy = legitimacy
        self.max_jail_term = max_jail_term
        self.active_threshold = active_threshold
        self.arrest_prob_constant = arrest_prob_constant
        self.movement = movement
        self.initial_unemployment_rate = initial_unemployment_rate
        self.corruption_level = corruption_level
        self.susceptible_level = susceptible_level
        self.max_iters = max_iters
        self.iteration = 0
        self.schedule = RandomActivation(self)
        self.grid = Grid(height, width, torus=True)
        model_reporters = {
            "Quiescent":
            lambda m: self.count_type_citizens(m, "Quiescent"),
            "Active":
            lambda m: self.count_type_citizens(m, "Active"),
            "Jailed":
            lambda m: self.count_jailed(m),
            "Employed":
            lambda m: self.count_employed(m),
            "Corrupted":
            lambda m: self.count_moral_type_citizens(m, "Corrupted"),
            "Honest":
            lambda m: self.count_moral_type_citizens(m, "Honest"),
            "Susceptible":
            lambda m: self.count_moral_type_citizens(m, "Susceptible")
        }
        agent_reporters = {
            "x": lambda a: a.pos[0],
            "y": lambda a: a.pos[1],
            "breed": lambda a: a.breed,
            "jail_sentence": lambda a: getattr(a, "jail_sentence", None),
            "condition": lambda a: getattr(a, "condition", None),
            "arrest_probability":
            lambda a: getattr(a, "arrest_probability", None),
            "is_employed": lambda a: getattr(a, "is_employed", None),
            "moral_condition": lambda a: getattr(a, "moral_condition", None),
        }
        self.datacollector = DataCollector(model_reporters=model_reporters,
                                           agent_reporters=agent_reporters)
        unique_id = 0
        if self.cop_density + self.citizen_density > 1:
            raise ValueError(
                "Cop density + citizen density must be less than 1")

        if self.initial_unemployment_rate > 1:
            raise ValueError(
                "initial_unemployment_rate must be between [0,1] ")

        if self.corruption_level + self.susceptible_level > 1:
            raise ValueError("moral level must be less than 1 ")

        for (contents, x, y) in self.grid.coord_iter():
            if self.random.random() < self.cop_density:
                cop = Cop(unique_id, self, (x, y), vision=self.cop_vision)
                unique_id += 1
                self.grid[y][x] = cop
                self.schedule.add(cop)
            elif self.random.random() < (self.cop_density +
                                         self.citizen_density):
                moral_state = "Honest"
                is_employed = 1
                if self.random.random() < self.initial_unemployment_rate:
                    is_employed = 0
                p = self.random.random()
                if p < self.corruption_level:
                    moral_state = "Corrupted"
                elif p < self.corruption_level + self.susceptible_level:
                    moral_state = "Susceptible"

                citizen = Citizen(
                    unique_id,
                    self,
                    (x, y),
                    #updated hardship formula: if agent is employed hardship is alleviated
                    hardship=self.random.random() -
                    (is_employed * self.random.uniform(0.05, 0.15)),
                    legitimacy=self.legitimacy,
                    #updated regime legitimacy, so inital corruption rate is taken into consideration
                    regime_legitimacy=self.legitimacy - self.corruption_level,
                    risk_aversion=self.random.random(),
                    active_threshold=self.active_threshold,
                    #updated threshold: if agent is employed threshold for rebelling is raised
                    threshold=self.active_threshold +
                    (is_employed * self.random.uniform(0.05, 0.15)),
                    vision=self.citizen_vision,
                    is_employed=is_employed,
                    moral_state=moral_state,
                )
                unique_id += 1
                self.grid[y][x] = citizen
                self.schedule.add(citizen)

        self.running = True
        self.datacollector.collect(self)

    def step(self):
        """
        Advance the model by one step and collect data.
        """
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)
        self.iteration += 1
        if self.iteration > self.max_iters:
            self.running = False

    @staticmethod
    def count_type_citizens(model, condition, exclude_jailed=False):
        """
        Helper method to count agents by Quiescent/Active.
        """
        count = 0
        for agent in model.schedule.agents:
            if agent.breed == "cop":
                continue
            if exclude_jailed and agent.jail_sentence:
                continue
            if agent.condition == condition:
                count += 1
        return count

    @staticmethod
    def count_moral_type_citizens(model,
                                  moral_condition,
                                  exclude_jailed=False):
        """
        Helper method to count agents by Quiescent/Active.
        """
        count = 0
        for agent in model.schedule.agents:
            if agent.breed == "cop":
                continue
            if exclude_jailed and agent.jail_sentence:
                continue
            if agent.moral_state == moral_condition:
                count += 1
        return count

    @staticmethod
    def count_jailed(model):
        """
        Helper method to count jailed agents.
        """
        count = 0
        for agent in model.schedule.agents:
            if agent.breed == "citizen" and agent.jail_sentence:
                count += 1
        return count

    @staticmethod
    def count_employed(model):
        """
        Helper method to count employed agents.
        """
        count = 0
        for agent in model.schedule.agents:
            if agent.breed == "cop":
                continue
            if agent.is_employed == 1:
                count += 1
        return count

    @staticmethod
    def count_corrupted(model):
        """
        Helper method to count corrupted agents.
        """
        count = 0
        for agent in model.schedule.agents:
            if agent.breed == "cop":
                continue
            if agent.is_corrupted == 1:
                count += 1
        return count
Example #35
0
class Schelling(Model):
    """Model class for the Schelling segregation model."""
    def __init__(
        self,
        height=20,
        width=20,
        density=0.8,
        minority_pc=0.2,
        homophily=3,
        education_boost=0,
        education_pc=0.2,
        seed=None,
    ):
        """Seed is used to set randomness in the __new__ function of the Model superclass."""
        # pylint: disable-msg=unused-argument,super-init-not-called

        self.height = height
        self.width = width
        self.density = density
        self.minority_pc = minority_pc
        self.homophily = homophily
        self.education_boost = education_boost
        self.education_pc = education_pc

        self.schedule = RandomActivation(self)
        self.grid = SingleGrid(height, width, torus=True)

        self.happy = 0
        self.datacollector = DataCollector(
            {"happy": "happy"},  # Model-level count of happy agents
            # For testing purposes, agent's individual x and y
            {
                "x": lambda a: a.pos[0],
                "y": lambda a: a.pos[1]
            },
        )

        # Set up agents
        # We use a grid iterator that returns
        # the coordinates of a cell as well as
        # its contents. (coord_iter)
        for cell in self.grid.coord_iter():
            x_coord = cell[1]
            y_coord = cell[2]
            if self.random.random() < self.density:
                if self.random.random() < self.minority_pc:
                    agent_type = 1
                else:
                    agent_type = 0

                agent_homophily = homophily
                if self.random.random() < self.education_pc:
                    agent_homophily += self.education_boost

                agent = SchellingAgent((x_coord, y_coord), self, agent_type,
                                       agent_homophily)
                self.grid.position_agent(agent, (x_coord, y_coord))
                self.schedule.add(agent)

        self.running = True
        self.datacollector.collect(self)

    def step(self):
        """Run one step of the model. If All agents are happy, halt the model."""
        self.happy = 0  # Reset counter of happy agents
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

        if self.happy == self.schedule.get_agent_count():
            self.running = False
    def __init__(self, height = 50, width = 50, initial_population =200, \
                 Moore = False, torus = True, regrow = 1, seed = None):
        '''
        Args:
            height - y axis of grid_size
            width - x axis of grid size
            initial_population - number of agents starting
            moore - type of neighborhood
            torus - whether or no world wraps
            regrow - amout each resource grows bas each step
            process - Number of additonal proces by agents
            0 = Movement/Survive; 1 = +trade, 2 = +
            
        Initial Parameters: 
            Multigrid
            ActivationbyBreed (see schedule)
            Num_Agents counter to account for each agent number
            timekeeper - dictionary to keep track of time for each section
            start_time - create initial time
            datacollector to collect agent data of model
        '''

        self.step_num = 0
        self.height = height
        self.width = width
        self.initial_population = initial_population
        self.num_agents = 0
        #Mesa Agent Scheduler
        #self.schedule = schedule.RandomActivationByBreed(self)
        self.schedule = RandomActivationByBreed(self)
        self.grid = MultiGrid(self.height, self.width, torus=True)
        self.regrow = regrow
        self.running = True
        self.price_record = defaultdict(list)
        '''
        Recorders
          Start datacollector
          Start time recorder
        '''
        self.start_time = time.time()

        self.datacollector = DataCollector(\

                             tables = {"Time":["Time Per Step"]})
        '''
        
        Creates the landscape:
            Fours mounds 2 sugar, 2 spice located- 1 in each quadrant
            imports landscape module to account for various landscape sizes
        '''
        self.resource_dict = {}

        landscape = Landscape.create_landscape(height, width)
        #places resources from landscape on grid
        for k, v in landscape.items():
            resource = R.resource(k, self, v, self.regrow)
            self.grid.place_agent(resource, (resource.pos[0], resource.pos[1]))
            #POINT
            self.schedule.add(resource)

        #fills in empty grids with null value resource agent
        #Deviation from GrAS -- in empty cells has random resource from 0 to 4
        for a, x, y in self.grid.coord_iter():
            if a == set():
                resource = R.resource((x,y), self, \
                                      (self.random.randrange(0,2), \
                                       self.random.randrange(0,2)),self.regrow)
                self.grid.place_agent(resource,
                                      (resource.pos[0], resource.pos[1]))
                #POINT
                self.schedule.add(resource)
        '''
        Creates the agents:
            
        '''
        pos_array = list(self.schedule.agents_by_breed['resource'].keys())
        self.random.shuffle(pos_array)
        vision_array = np.random.randint(4, 6, self.initial_population)
        spice_array = np.random.randint(1, 6, self.initial_population)
        sugar_array = np.random.randint(1, 6, self.initial_population)
        for n in range(self.initial_population):
            #x = 0
            #y = 0
            #print ("position: ", (n, x,y))
            #GrAS p. 108
            sugar = self.random.randrange(25, 50)
            spice = self.random.randrange(25, 50)
            #GrAS p.108
            sug_bolism = sugar_array[n]
            spice_bolism = spice_array[n]
            #GrAS p. 108
            vision = vision_array[n]
            neighbors = Moore
            a = N.NetAgent(n, pos_array[n], self, \
                                 {"sug_bolism": sug_bolism, \
                                 "spice_bolism": spice_bolism}, \
                                 {1 : sugar, 2: spice}, {"vision": vision}, \
                                 neighbors)
            #POINT
            self.schedule.add(a)
            self.grid.place_agent(a, pos_array[n])
Example #37
0
    def __init__(self, init_seed, height, width, density, minority_pc, homophily, virtuous_homophily, nudge_amount, num_to_argue, num_to_convert, convert_prob, convinced_threshold \
            , random_move_prob, traditionless_life_decrease, vir_a, vir_b, vir_c, emo_a, emo_b \
            , emo_c , emo_bias_a, emo_bias_b, emo_bias_c , strongest_belief_weight, count_extra_pow, count_extra_det \
            , count_extra_det_pow, extra_pow, extra_det , belief_of_extra_pow, belief_of_extra_det, belief_of_extra_det_pow):

        # uncomment to make runs reproducible
        super().__init__(seed=init_seed)

        self.height = height
        self.width = width
        self.density = density
        self.minority_pc = minority_pc
        # segregation logic taken from the Schelling segregation model example
        self.homophily = homophily
        self.virtuous_homophily = virtuous_homophily
        self.convert_prob = convert_prob
        self.num_to_convert = num_to_convert
        self.traditionless_life_decrease = traditionless_life_decrease
        self.steps_since = 0

        self.schedule = RandomActivation(self)
        self.grid = SingleGrid(height, width, torus=True)

        self.happy = 0
        self.convinced = 0
        self.virtuous_count = 0
        self.emotivist_count = 0
        self.virtuous_death_count = 0
        self.datacollector = DataCollector( # Model-level variables for graphs
            {"happy": "happy", "convinced": "convinced", "emotivist_count": "emotivist_count" \
                , "virtuous_count": "virtuous_count", "virtuous_death_count": "virtuous_death_count"},
            {"x": lambda a: a.pos[0], "y": lambda a: a.pos[1], "happy": lambda a: a.happy, # Agent-level variables
            "convinced": lambda a: a.convinced, "strongest_belief": lambda a: a.strongest_belief()
            , "beliefs": lambda a: a.beliefs_string(), "type": lambda a: 0 if isinstance(a, EmotivistAgent) else 1})

        self.nudge_amount = nudge_amount
        self.num_to_argue = num_to_argue
        self.convinced_threshold = convinced_threshold
        self.random_move_prob = random_move_prob

        population = [
            "A", "B", "C"
        ]  # defined here because of dependencies on the visualization side (emo_bias in server.py)
        self.population = population
        probs_emotivist = np.array([emo_a, emo_b, emo_c])
        probs_emotivist = probs_emotivist / np.sum(
            probs_emotivist)  # normalize probs to 1.0
        probs_virtuous = np.array([vir_a, vir_b, vir_c])
        probs_virtuous = probs_virtuous / np.sum(probs_virtuous)
        initial_bias_emotivist = {
            "A": emo_bias_a,
            "B": emo_bias_b,
            "C": emo_bias_c
        }
        self.strongest_belief_weight = strongest_belief_weight

        # Set up agents
        # We get a list of cells in order from the grid iterator
        # and randomize the list
        cell_list = list(self.grid.coord_iter())
        random.shuffle(cell_list)
        total_num_agents = self.density * self.width * self.height

        det_emotivists_added = 0
        pow_emotivists_added = 0
        det_pow_emotivists_added = 0

        # pregenerate a list of strongest_beliefs in random order according to distribution
        # currently only works with a population of 3 beliefs
        list_emotivist_choices = []
        emo_length = ceil((1.0 - self.minority_pc) * total_num_agents)
        for i in range(0, emo_length):
            if (float(i) / emo_length < probs_emotivist[0]):
                list_emotivist_choices.append(population[0])
            elif (float(i) / emo_length <
                  probs_emotivist[0] + probs_emotivist[1]):
                list_emotivist_choices.append(population[1])
            else:
                list_emotivist_choices.append(population[2])

        random.shuffle(list_emotivist_choices)

        list_virtuous_choices = []
        vir_length = ceil(self.minority_pc * total_num_agents)
        for i in range(0, vir_length):
            if (float(i) / vir_length < probs_virtuous[0]):
                list_virtuous_choices.append(population[0])
            elif (float(i) / vir_length <
                  probs_virtuous[0] + probs_virtuous[1]):
                list_virtuous_choices.append(population[1])
            else:
                list_virtuous_choices.append(population[2])

        random.shuffle(list_virtuous_choices)

        # create agents and add to grid
        i = 0
        for cell in cell_list:
            x = cell[1]
            y = cell[2]
            if i < total_num_agents:
                if i < self.minority_pc * total_num_agents:
                    #initial_strongestbelief_virtuous = random.choices(population, weights=probs_virtuous, k=1)[0]
                    initial_strongestbelief_virtuous = list_virtuous_choices.pop(
                    )
                    initial_beliefs_virtuous = {}
                    for belief in population:
                        if (belief == initial_strongestbelief_virtuous):
                            initial_beliefs_virtuous[
                                belief] = strongest_belief_weight
                        else:
                            initial_beliefs_virtuous[belief] = (
                                1 - strongest_belief_weight) / (
                                    len(population) - 1)
                    agent = VirtuousAgent(i, (x, y), self,
                                          initial_beliefs_virtuous)
                    self.virtuous_count += 1
                else:
                    #agent_type = 0
                    #initial_strongestbelief_emotivist = random.choices(population, weights=probs_emotivist, k=1)[0]
                    initial_strongestbelief_emotivist = list_emotivist_choices.pop(
                    )
                    initial_beliefs_emotivist = {}
                    det = 0.0
                    pow = 1.0
                    if (initial_strongestbelief_emotivist
                            == belief_of_extra_det
                            and det_emotivists_added < count_extra_det):
                        det = extra_det
                        det_emotivists_added += 1
                    elif (initial_strongestbelief_emotivist
                          == belief_of_extra_pow
                          and pow_emotivists_added < count_extra_pow):
                        pow = extra_pow
                        pow_emotivists_added += 1
                    elif (initial_strongestbelief_emotivist
                          == belief_of_extra_det_pow
                          and det_pow_emotivists_added < count_extra_det_pow):
                        pow = extra_pow
                        det_pow_emotivists_added += 1

                    for belief in population:
                        if (belief == initial_strongestbelief_emotivist):
                            initial_beliefs_emotivist[
                                belief] = strongest_belief_weight
                        else:
                            initial_beliefs_emotivist[belief] = (
                                1 - strongest_belief_weight) / (
                                    len(population) - 1)

                    agent = EmotivistAgent(i, (x, y), self,
                                           initial_beliefs_emotivist,
                                           initial_bias_emotivist, pow, det)
                    self.emotivist_count += 1

                i += 1
                self.grid.position_agent(agent, (x, y))
                self.schedule.add(agent)

        self.last_agent_id = i
        # update message with starting probs
        self.message = "Emotivist probs: " + str(list(map(lambda x: "{:.2f}".format(x), probs_emotivist.tolist()))) \
                + ", Virtuous probs: " + str(list(map(lambda x: "{:.2f}".format(x), probs_virtuous.tolist())))
        self.running = True
        self.datacollector.collect(self)
Example #38
0
    def __init__(self, no_people, total_area, no_agents, Nc_N, n, all_x, all_y,
                 centers, infection_rate, city_label, first_infected):
        self.num_agents = no_agents
        grid_size = round(
            math.sqrt((self.num_agents / no_people) * total_area) * 100)
        self.grid = MultiGrid(grid_size, grid_size, False)
        self.schedule = RandomActivation(self)
        self.running = True

        flux_store = np.zeros((1, 3))
        home_store1 = np.zeros((self.num_agents, 2))

        for i in range(round(len(centers) / 2)):
            print(i, datetime.datetime.now() - begin_time)
            n_cities = random.sample(range(1, round(len(centers) / 2)), n)

            for j in range(len(n_cities)):
                mi = np.count_nonzero(city_label == i + 1)
                nj = np.count_nonzero(city_label == n_cities[j])
                radius = math.sqrt(
                    (centers[i, 0] - centers[n_cities[j], 0])**2 +
                    (centers[i, 1] - centers[n_cities[j], 1])**2)
                sij = 0

                for k in range(len(all_x)):
                    if (all_x[k] - centers[i, 0])**2 + (
                            all_y[k] - centers[i, 1])**2 < radius**2:
                        sij += 1

                sij = sij - mi - nj
                if sij < 0:
                    sij = 0

                try:
                    Tij = (mi * Nc_N * mi * nj) / ((mi + sij) *
                                                   (mi + nj + sij)) * 10
                except ZeroDivisionError:
                    Tij = 0

                if Tij > 75:
                    Tij = 75

                if Tij > 1 and (i != n_cities[j]):
                    flux_store = np.vstack(
                        (flux_store, (Tij, i + 1, n_cities[j])))

        work_place = np.zeros(self.num_agents)
        work_store1 = np.zeros((num, 2))
        flux_store = np.delete(flux_store, 0, 0)

        for i in np.unique(flux_store[:, 1]):
            place = np.where(flux_store[:, 1] == i)[0]
            place1 = np.where(city_label == i)[0]
            for j in place1:
                for k in place:
                    if random.uniform(0, 100) < flux_store[k, 0]:
                        work_place[j] = flux_store[k, 2]

        for i in range(len(work_store1)):
            if work_place[i] != 0:
                n = int(work_place[i])
                work_store1[i, :] = centers[n, 0], centers[n, 1]

        for i in range(self.num_agents):
            home_store1[i, :] = int(all_x[i]), int(all_y[i])

        work_store = np.int64(work_store1)
        home_store = np.int64(home_store1)

        for i in range(self.num_agents):
            a = Agent(i, self, infection_rate, work_store, home_store)
            self.schedule.add(a)
            self.grid.place_agent(a, (int(all_x[i]), int(all_y[i])))

            if i == first_infected:
                a.infected = 1

        self.datacollector = DataCollector(
            model_reporters={"Tot informed": compute_informed},
            agent_reporters={"Infected": "infected"})
Example #39
0
class VirusModel(Model):
    def __init__(self, num_nodes, avg_node_degree, initial_outbreak_size, alpha, beta, gamma, delta, k, n):

        self.num_nodes = num_nodes
        self.avg_node_degree = avg_node_degree
        self.G = nx.barabasi_albert_graph(n=self.num_nodes,m=avg_node_degree)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.initial_outbreak_size = initial_outbreak_size if initial_outbreak_size <= num_nodes else num_nodes
        self.alpha = alpha
        self.beta = beta
        self.gamma = gamma
        self.delta = delta

        self.k=k
        self.n=n

        # Create agents
        for i, node in enumerate(self.G.nodes()):
            a = VirusAgent(i, self, State.SUSCEPTIBLE, self.alpha, self.beta, self.gamma, self.delta, self.k, self.n)
            self.schedule.add(a)
            # Add the agent to the node
            self.grid.place_agent(a, node)

        # Infect some nodes
        active_nodes = random.sample(self.G.nodes(), self.initial_outbreak_size)
        for a in self.grid.get_cell_list_contents(active_nodes):
            a.state = State.ACTIVE

        self.datacollector = DataCollector(
            model_reporters={
                             "Infected": number_active,
                             "Susceptible": number_susceptible,
                             "Carrier": number_inactive,
                             "Removed": number_removed,
                             "Active Clustering": infective_clustering,
                             "Exposed Clustering": exposed_clustering,
                             "Infective Diffusion": infective_diffusion,
                             "Exposed Diffusion": exposed_diffusion
                             }
        )

        self.running = True
        self.datacollector.collect(self)

    def removed_susceptible_ratio(self):
        try:
            return number_state(self, State.REMOVED) / number_state(self, State.SUSCEPTIBLE)
        except ZeroDivisionError:
            return math.inf

    def tyrant_remove(self):
        if number_active(self) > 0:
            if random.random() < 0.002:
                actives = [a for a in self.grid.get_all_cell_contents() if a.state is State.ACTIVE]
                node_for_removal = random.sample(actives, 1)
                for a in node_for_removal:
                    a.state = State.REMOVED
        # for a in self.grid.get_cell_list_contents(active_nodes):
        #     a.state = State.ACTIVE

    def step(self):
        self.tyrant_remove()
        self.schedule.step()
        self.datacollector.collect(self)

    def run_model(self, n):
        for i in range(n):
            self.step()
Example #40
0
class SEIRX(Model):
    '''
    A model with a number of different agents that reproduces
    the SEIRX dynamics of pandemic spread in a facility. Note:
    all times are set to correspond to days

    G: networkx undirected graph, interaction graph between agents. Edges have
    to have edge the edge attribute 'contact_type' specifying the closeness of 
    contacts, which can be ['very far', 'far', 'intermediate' and 'close']. 
    Nodes have to have the node attribute 'type' which specifies the agent type
    of the given node (for example 'student' or 'teacher' in a school scenario).
    In addition, nodes can have the attribute 'unit', which assigns them to a
    unit in space (for example a 'class' in a school scenario).

    verbosity: integer in [0, 1, 2], controls text output to std out to track
    simulation progress and transmission dynamics. Default = 0.

    testing, default = 'diagnostic'  
        'diagnostic':   only diagnostic tests for symptomatic agents
        'background':   adds background screens of all agents after a positive 
                        diagnostic test
        'preventive':   adds preventive screens of agent groups in time 
                        intervals specified separately for each agent group in
                        the variable 'screening_interval' 

    infection_duration, default = 11 NOTE: includes the time an agent is exposed 
    but not yet infectious at the beginning of an infection
        positive integer:   mean or median of the infection duration in days
        list of two floats: mean and standard deviation of a distribution 
                            specifying the infection duration in days. These 
                            numbers will be used to construct a Weibull 
                            distribution from which the infection duration will 
                            be drawn for every agent individually

    exposure_duration, default = 4. Sets the time from transmission to becoming 
    infectious
        positive integer:   mean or median of the exposure duration in days
        list of two floats: mean and standard deviation of a distribution 
                            specifying the exposure duration in days. These 
                            numbers will be used to construct a Weibull 
                            distributoin from which the exposure duration will 
                            be drawn for every agent individually.

    time_until_symptoms, default = 6. Sets the time from transmission to 
    (potentially) developing symptoms. Symptom probability has to be set for
    each agent group individually using the parameter 'symptom_probability'
        positive integer:   mean or median of the time until symptoms in days
        list of two floats: mean and standard deviation of a distribution 
                            specifying the time until symptoms in days. These 
                            numbers will be used to construct a Weibull 
                            distribution from which the time until symptoms will
                            be drawn for every agent individually.

    quarantine_duration, default = 14. Positive integer, sets the time a 
    positively tested agent is quarantined in days

    infection_risk_contact_type_weights: dictionary of the form
    {'very_far':float, 'far':float, 'intermediate':float, 'close':float}
    that sets transmission risk multipliers for different contact types of
    agents specified in the contact network G. Default: {'very_far': 0.1,
    'far': 0.5, 'intermediate': 1, 'close': 3}

    subclinical_modifier: default = 1.0. Float, modifies the infectiousness of 
    asymptomatic cases. Example: if subclinical_modifier = 0.5, the 
    infectiousness of an asymptomatic case will be reduced to 50%.

    K1_contact_types: list of strings from ['very_far', 'far', 'intermediate',
    'close']. Definition of contact types for which agents are considered 
    "K1 contact persons" if they had contact to a positively tested person wtith 
    a specified contact intensity. Default = ['close'].

    diagnostic_test_type, default = 'one_day_PCR'. String, specifies the test 
    technology and test result turnover time used for diagnostic testing. For 
    example 'same_day_antigen' or 'two_day_PCR'. See module "Testing" for 
    different implemented testing techologies.

    preventive_screening_test_type:, default = 'one_day_PCR', String, specifies 
    the test technology and test result turnover time used for preventive 
    sreening. For example 'same_day_antigen' or 'two_day_PCR'. See module 
    "Testing" for different implemented testing techologies.

    follow_up_testing_interval, default = None. Positive integer, sets the time 
    a follow-up screen (background screen) is initiated after an initial screen 
    triggered by a positive test result. Only applies if the testing strategy is
    'background' or preventive.

    liberating_testing, default = False. Boolean, flag that specifies, whether 
    or not an agent is released from quarantine after returning a negative test 
    result.

	index_case, default = 'employee' (nursing home scenario) or 'teacher' 
    (school scenario). Specifies how infections are introduced into the facility.
        agent_type:     If an agent type (for example 'student' or 'teacher' in 
                        the school scenario) is specified, a single randomly
                        chosen agent from this agent group will become the index
                        case and no further index cases will be introduced into
                        the scenario.
        'continuous':   In this case, agents have a continuous risk to become 
                        index cases in every simulation step. The risk has to
                        be specified for every agent group individually, using
                        the 'index_probability' parameter. If only a single
                        agent group has a non-zero index probability, then only
                        agents from this group can become index cases.


	agent_types: dictionary of the structure
		{
		agent type:
			{
			screening interval : integer, number of days between each preventive
			screen in this agent group

			index probability : float in the range [0, 1], sets the probability
			to become an index case in each time step

			mask : bool
                whether or not the agent type is wearing a mask
			}
		}

	The dictionary's keys are the names of the agent types which have to
	correspond to the node attributes in the contact graph. The screening
	interval sets the time-delay between preventive screens of this agent group,
	the index probability sets the probability of a member of this agent group
	becoming an index case in every time step

    seed: positive integer, fixes the seed of the simulation to enable
    repeatable simulation runs. If seed = None, the simulation will be 
    initialized at random.
    '''

    def __init__(self, G,
        verbosity = 0,
        base_transmission_risk = 0.05,
        testing='diagnostic',
        exposure_duration = [5.0, 1.9],
        time_until_symptoms = [6.4, 0.8],
        infection_duration = [10.91, 3.95],
        quarantine_duration = 10,
        subclinical_modifier = 0.6,
        infection_risk_contact_type_weights = {
            'very_far': 0.1,
            'far': 0.25,
            'intermediate': 0.5,
            'close': 1},
        K1_contact_types = ['close'],
        diagnostic_test_type = 'one_day_PCR',
        preventive_screening_test_type = 'same_day_antigen',
        follow_up_testing_interval = None,
        liberating_testing = False,
        index_case = 'teacher',
        agent_types = {
            'teacher':      {'screening_interval': None,
                             'index_probability': 0,
                             'mask':False},
            'student':      {'screening_interval': None,
                             'index_probability': 0,
                             'mask':False},
            'family_member':{'screening_interval': None,
                             'index_probability': 0,
                             'mask':False}},
        age_transmission_risk_discount = \
             {'slope':-0.02,
              'intercept':1},
        age_symptom_discount = \
             {'slope':-0.02545,
              'intercept':0.854545},
        mask_filter_efficiency = {'exhale':0, 'inhale':0},
        transmission_risk_ventilation_modifier = 0,
        seed = None):

        # mesa models already implement fixed seeds through their own random
        # number generations. Sadly, we need to use the Weibull distribution
        # here, which is not implemented in mesa's random number generation
        # module. Therefore, we need to initialize the numpy random number
        # generator with the given seed as well
        if seed != None:
            np.random.seed(seed)

        # sets the (daily) transmission risk for a household contact without
        # any precautions. Target infection ratios are taken from literature
        # and the value of the base_transmission_risk is calibrated such that
        # the simulation produces the correct infection ratios in a household
        # setting with the given distributions for epidemiological parameters
        # of agents
        self.base_transmission_risk = base_transmission_risk
        # sets the level of detail of text output to stdout (0 = no output)
        self.verbosity = check_positive_int(verbosity)
        # flag to turn off the testing & tracing strategy
        self.testing = check_testing(testing)
        self.running = True  # needed for the batch runner implemented by mesa
        # set the interaction mode to simultaneous activation
        self.schedule = SimultaneousActivation(self)

        # internal step counter used to launch screening tests
        self.Nstep = 0

        # since we may have weekday-specific contact networks, we need
        # to keep track of the day of the week. Since the index case
        # per default is introduced at step 0 in index case mode, we
        # need to offset the starting weekday by a random number of weekdays
        # to prevent artifacts from always starting on the same day of the week

        self.weekday_offset = self.random.randint(1, 8)
        self.weekday = self.Nstep + self.weekday_offset

        ## epidemiological parameters: can be either a single integer or the
        # mean and standard deviation of a distribution
        self.epi_params = {}
        # counter to track the number of pathological parameter combinations
        # that had to be re-rolled (only here for debugging and control reasons)
        self.param_rerolls = 0

        for param, param_name in zip(
            [exposure_duration, time_until_symptoms, infection_duration],
            ['exposure_duration', 'time_until_symptoms', 'infection_duration'
             ]):

            if isinstance(param, int):
                self.epi_params[param_name] = check_positive_int(param)

            elif isinstance(param, list) and len(param) == 2:

                mu = check_positive(param[0])
                var = check_positive(param[1]**2)
                shape = root_scalar(get_weibull_shape,
                                    args=(mu, var),
                                    method='toms748',
                                    bracket=[0.2, 500]).root
                scale = get_weibull_scale(mu, shape)

                self.epi_params[param_name] = [shape, scale]
            else:
                print('{} format not recognized, should be either a single '+\
                  'int or a tuple of two positive numbers'.format(param_name))

        # duration of quarantine
        self.quarantine_duration = check_positive_int(quarantine_duration)

        self.infection_risk_area_weights = check_contact_type_dict(
            infection_risk_contact_type_weights)

        # modifier for infectiosness for asymptomatic cases
        self.subclinical_modifier = check_positive(subclinical_modifier)
        # modifiers for the infection risk, depending on contact type
        self.infection_risk_contact_type_weights = infection_risk_contact_type_weights

        # discounts for age-dependent transmission and reception risks and
        # symptom probabilities
        self.age_transmission_risk_discount = \
            check_discount(age_transmission_risk_discount)
        self.age_symptom_discount = \
            check_discount(age_symptom_discount)

        self.mask_filter_efficiency = mask_filter_efficiency
        self.transmission_risk_ventilation_modifier = \
            transmission_risk_ventilation_modifier

        ## agents and their interactions
        # interaction graph of agents
        self.G = check_graph(G)
        # add weights as edge attributes so they can be visualised easily
        if type(self.G) == nx.MultiGraph:
            for (u, v, key, contact_type) in self.G.edges(keys=True,
                                                          data='contact_type'):
                self.G[u][v][key]['weight'] = \
                    self.infection_risk_contact_type_weights[contact_type]
        else:
            for e in G.edges(data=True):
                G[e[0]][e[1]]['weight'] = self.infection_risk_contact_type_weights\
                 [G[e[0]][e[1]]['contact_type']]

        # extract the different agent types from the contact graph
        self.agent_types = list(agent_types.keys())
        # dictionary of available agent classes with agent types and classes
        self.agent_classes = {}
        if 'resident' in agent_types:
            from scseirx.agent_resident import resident
            self.agent_classes['resident'] = resident
        if 'employee' in agent_types:
            from scseirx.agent_employee import employee
            self.agent_classes['employee'] = employee
        if 'student' in agent_types:
            from scseirx.agent_student import student
            self.agent_classes['student'] = student
        if 'teacher' in agent_types:
            from scseirx.agent_teacher import teacher
            self.agent_classes['teacher'] = teacher
        if 'family_member' in agent_types:
            from scseirx.agent_family_member import family_member
            self.agent_classes['family_member'] = family_member

        ## set agent characteristics for all agent groups
        # list of agent characteristics
        params = [
            'screening_interval', 'index_probability', 'mask',
            'voluntary_testing_rate'
        ]

        # default values that are used in case a characteristic is not specified
        # for an agent group
        defaults = {
            'screening_interval': None,
            'index_probability': 0,
            'mask': False,
            'voluntary_testing_rate': 1
        }

        # sanity checks that are applied to parameters passed to the class
        # constructor to make sure they conform to model expectations
        check_funcs = [
            check_positive_int, check_probability, check_bool,
            check_probability
        ]

        # member dicts that store the parameter values for each agent group
        self.screening_intervals = {}
        self.index_probabilities = {}
        self.masks = {}
        self.voluntary_testing_rates = {}

        param_dicts = [
            self.screening_intervals, self.index_probabilities, self.masks,
            self.voluntary_testing_rates
        ]

        # iterate over all possible agent parameters and agent groups: set the
        # respective value to the value passed through the constructor or to
        # the default value if no value has been passed
        for param, param_dict, check_func in zip(params, param_dicts,
                                                 check_funcs):
            for at in self.agent_types:
                try:
                    param_dict.update({at: check_func(agent_types[at][param])})
                except KeyError:
                    param_dict.update({at: defaults[param]})

        # pass all parameters relevant for the testing strategy to the testing
        # class. NOTE: this separation is not a strictly necessary design
        # decision but I like to keep the parameters related to testing and
        # tracing in a separate place
        self.Testing = Testing(self, diagnostic_test_type,
                               preventive_screening_test_type,
                               check_positive_int(follow_up_testing_interval),
                               self.screening_intervals,
                               check_bool(liberating_testing),
                               check_K1_contact_types(K1_contact_types),
                               verbosity)

        # specifies either continuous probability for index cases in agent
        # groups based on the 'index_probability' for each agent group, or a
        # single (randomly chosen) index case in the passed agent group
        self.index_case = check_index_case(index_case, self.agent_types)

        self.num_agents = {}

        ## add agents
        # extract the agent nodes from the graph and add them to the scheduler
        for agent_type in self.agent_types:
            IDs = [x for x, y in G.nodes(data=True) if y['type'] == agent_type]
            self.num_agents.update({agent_type: len(IDs)})

            # get the agent locations (units) from the graph node attributes
            units = [self.G.nodes[ID]['unit'] for ID in IDs]
            for ID, unit in zip(IDs, units):

                tmp_epi_params = {}
                # for each of the three epidemiological parameters, check if
                # the parameter is an integer (if yes, pass it directly to the
                # agent constructor), or if it is specified by the shape and
                # scale parameters of a Weibull distribution. In the latter
                # case, draw a new number for every agent from the distribution
                # NOTE: parameters drawn from the distribution are rounded to
                # the nearest integer
                while True:
                    for param_name, param in self.epi_params.items():
                        if isinstance(param, int):
                            tmp_epi_params[param_name] = param

                        else:
                            tmp_epi_params[param_name] = \
                                round(weibull_two_param(param[0], param[1]))

                    if tmp_epi_params['exposure_duration'] > 0 and \
                       tmp_epi_params['time_until_symptoms'] >= \
                       tmp_epi_params['exposure_duration'] and\
                       tmp_epi_params['infection_duration'] > \
                       tmp_epi_params['exposure_duration']:
                        break
                    else:
                        self.param_rerolls += 1
                        if verbosity > 1:
                            print('pathological epi-param case found!')
                            print(tmp_epi_params)

                # check if the agent participates in voluntary testing
                p = self.voluntary_testing_rates[agent_type]
                voluntary_testing = np.random.choice([True, False],
                                                     p=[p, 1 - p])

                a = self.agent_classes[agent_type](
                    ID, unit, self, tmp_epi_params['exposure_duration'],
                    tmp_epi_params['time_until_symptoms'],
                    tmp_epi_params['infection_duration'], voluntary_testing,
                    verbosity)
                self.schedule.add(a)

# infect the first agent in single index case mode
        if self.index_case != 'continuous':
            infection_targets = [
                a for a in self.schedule.agents if a.type == index_case
            ]
            # pick a random agent to infect in the selected agent group
            target = self.random.randint(0, len(infection_targets) - 1)
            infection_targets[target].exposed = True
            if self.verbosity > 0:
                print('{} exposed: {}'.format(index_case,
                                              infection_targets[target].ID))

        # list of agents that were tested positive this turn
        self.newly_positive_agents = []
        # flag that indicates if there were new positive tests this turn
        self.new_positive_tests = False
        # dictionary of flags that indicate whether a given agent group has
        # been creened this turn
        self.screened_agents = {
            'reactive': {agent_type: False
                         for agent_type in self.agent_types},
            'follow_up':
            {agent_type: False
             for agent_type in self.agent_types},
            'preventive':
            {agent_type: False
             for agent_type in self.agent_types}
        }

        # dictionary of counters that count the days since a given agent group
        # was screened. Initialized differently for different index case modes
        if (self.index_case == 'continuous') or \
          (not np.any(list(self.Testing.screening_intervals.values()))):
            self.days_since_last_agent_screen = {
                agent_type: 0
                for agent_type in self.agent_types
            }
        # NOTE: if we initialize these variables with 0 in the case of a single
        # index case, we introduce a bias since in 'single index case mode' the
        # first index case will always become exposed in step 0. To realize
        # random states of the preventive sceening procedure with respect to the
        # incidence of the index case, we have to randomly pick the days since
        # the last screen for the agent group from which the index case is
        else:
            self.days_since_last_agent_screen = {}
            for agent_type in self.agent_types:
                if self.Testing.screening_intervals[agent_type] != None:
                    self.days_since_last_agent_screen.update({
                        agent_type:
                        self.random.choice(
                            range(
                                0,
                                self.Testing.screening_intervals[agent_type] +
                                1))
                    })
                else:
                    self.days_since_last_agent_screen.update({agent_type: 0})

        # dictionary of flags that indicates whether a follow-up screen for a
        # given agent group is scheduled
        self.scheduled_follow_up_screen = {
            agent_type: False
            for agent_type in self.agent_types
        }

        # counters
        self.number_of_diagnostic_tests = 0
        self.number_of_preventive_screening_tests = 0
        self.positive_tests = {
            self.Testing.preventive_screening_test_type:
            {agent_type: 0
             for agent_type in self.agent_types},
            self.Testing.diagnostic_test_type:
            {agent_type: 0
             for agent_type in self.agent_types}
        }

        self.undetected_infections = 0
        self.predetected_infections = 0
        self.pending_test_infections = 0
        self.quarantine_counters = {
            agent_type: 0
            for agent_type in agent_types.keys()
        }
        self.false_negative = 0

        # data collectors to save population counts and agent states every
        # time step
        self.datacollector = DataCollector(
            model_reporters=
             {
             'N_diagnostic_tests':get_N_diagnostic_tests,
                'N_preventive_screening_tests':get_N_preventive_screening_tests,
                'diagnostic_test_detected_infections_student':\
                        get_diagnostic_test_detected_infections_student,
                'diagnostic_test_detected_infections_teacher':\
                        get_diagnostic_test_detected_infections_teacher,
                'diagnostic_test_detected_infections_family_member':\
                        get_diagnostic_test_detected_infections_family_member,
                'preventive_test_detected_infections_student':\
                        get_preventive_test_detected_infections_student,
                'preventive_test_detected_infections_teacher':\
                        get_preventive_test_detected_infections_teacher,
                'preventive_test_detected_infections_family_member':\
                        get_preventive_test_detected_infections_family_member,
                'undetected_infections':get_undetected_infections,
                'predetected_infections':get_predetected_infections,
                'pending_test_infections':get_pending_test_infections
                },

            agent_reporters=
             {
             'infection_state': get_infection_state,
                'quarantine_state': get_quarantine_state
                })

    ## transmission risk modifiers
    def get_transmission_risk_contact_type_modifier(self, source, target):
        # construct the edge key as combination between agent IDs and weekday
        n1 = source.ID
        n2 = target.ID
        tmp = [n1, n2]
        tmp.sort()
        n1, n2 = tmp
        key = n1 + n2 + 'd{}'.format(self.weekday)
        contact_weight = self.G.get_edge_data(n1, n2, key)['weight']

        # the link weight is a multiplicative modifier of the link strength.
        # contacts of type "close" have, by definition, a weight of 1. Contacts
        # of type intermediate, far or very far have a weight < 1 and therefore
        # are less likely to transmit an infection. For example, if the contact
        # type far has a weight of 0.2, a contact of type far has only a 20%
        # chance of transmitting an infection, when compared to a contact of
        # type close. To calculate the probability of success p in the Bernoulli
        # trial, we need to reduce the base risk (or base probability of success)
        # by the modifications introduced by preventive measures. These
        # modifications are formulated in terms of "probability of failure", or
        # "q". A low contact weight has a high probability of failure, therefore
        # we return q = 1 - contact_weight here.
        q1 = 1 - contact_weight

        return q1

    def get_transmission_risk_age_modifier_transmission(self, source):
        '''linear function such that at age 18 the risk is that of an adult (=1).
        The slope of the line needs to be calibrated.
        '''
        age = source.age
        max_age = 18
        if age <= max_age:
            age_weight = self.age_transmission_risk_discount['slope'] * \
                 np.abs(age - max_age) + self.age_transmission_risk_discount['intercept']

            # The age weight can be interpreted as multiplicative factor that
            # reduces the chance for transmission with decreasing age. The slope
            # of the age_transmission_discount function is the decrease (in % of
            # the transmission risk for an 18 year old or above) of transmission
            # risk with every year a person is younger than 18 (the intercept is
            # 1 by definition).
            # To calculate the probability of success p in the Bernoulli
            # trial, we need to reduce the base risk (or base probability of success)
            # by the modifications introduced by preventive measures. These
            # modifications are formulated in terms of "probability of failure", or
            # "q". A low age weight has a high probability of failure, therefore
            # we return q = 1 - age_weight here.
            q2 = 1 - age_weight
        else:
            q2 = 0

        return q2

    def get_transmission_risk_age_modifier_reception(self, target):
        '''linear function such that at age 18 the risk is that of an adult (=1).
        The slope of the line needs to be calibrated.
        '''
        age = target.age
        max_age = 18
        if age <= max_age:
            age_weight = self.age_transmission_risk_discount['slope'] * \
            np.abs(age - max_age) + self.age_transmission_risk_discount['intercept']
            # see description in get_transmission_risk_age_modifier_transmission
            q3 = 1 - age_weight
        else:
            q3 = 0

        return q3

    # infectiousness is constant and high until symptom onset and then
    # decreases monotonically until agents are not infectious anymore
    # at the end of the infection_duration
    def get_transmission_risk_progression_modifier(self, source):
        if source.days_since_exposure < source.exposure_duration:
            progression_weight = 0
        elif source.days_since_exposure <= source.time_until_symptoms:
            progression_weight = 1
        elif source.days_since_exposure > source.time_until_symptoms and \
             source.days_since_exposure <= source.infection_duration:
            # we add 1 in the denominator, such that the source is also
            # (slightly) infectious on the last day of the infection_duration
            progression_weight = \
                 (source.days_since_exposure - source.time_until_symptoms) / \
                 (source.infection_duration - source.time_until_symptoms + 1)
        else:
            progression_weight = 0
        # see description in get_transmission_risk_age_modifier_transmission
        q4 = 1 - progression_weight

        return q4

    def get_transmission_risk_subclinical_modifier(self, source):
        if source.symptomatic_course == False:
            subclinical_weight = self.subclinical_modifier
        else:
            subclinical_weight = 1
        # see description in get_transmission_risk_age_modifier_transmission
        q5 = 1 - subclinical_weight
        return q5

    def get_transmission_risk_exhale_modifier(self, source):
        if source.mask:
            exhale_weight = self.mask_filter_efficiency['exhale']
        else:
            exhale_weight = 1
        # see description in get_transmission_risk_age_modifier_transmission
        q6 = 1 - exhale_weight
        return q6

    def get_transmission_risk_inhale_modifier(self, target):
        if target.mask:
            inhale_weight = self.mask_filter_efficiency['inhale']
        else:
            inhale_weight = 1
        # see description in get_transmission_risk_age_modifier_transmission
        q7 = 1 - inhale_weight
        return q7

    def get_transmission_risk_ventilation_modifier(self):
        ventilation_weight = self.transmission_risk_ventilation_modifier
        # see description in get_transmission_risk_age_modifier_transmission
        q8 = 1 - ventilation_weight
        return q8

    def test_agent(self, a, test_type):
        a.tested = True
        a.pending_test = test_type
        if test_type == self.Testing.diagnostic_test_type:
            self.number_of_diagnostic_tests += 1
        else:
            self.number_of_preventive_screening_tests += 1

        if a.exposed:
            # tests that happen in the period of time in which the agent is
            # exposed but not yet infectious
            if a.days_since_exposure >= self.Testing.tests[test_type][
                    'time_until_testable']:
                if self.verbosity > 1:
                    print(
                        '{} {} sent positive sample (even though not infectious yet)'
                        .format(a.type, a.ID))
                a.sample = 'positive'
                self.predetected_infections += 1
                self.positive_tests[test_type][a.type] += 1
            else:
                if self.verbosity > 1:
                    print('{} {} sent negative sample'.format(a.type, a.ID))
                a.sample = 'negative'

        elif a.infectious:
            # tests that happen in the period of time in which the agent is
            # infectious and the infection is detectable by a given test
            if a.days_since_exposure >= self.Testing.tests[test_type]['time_until_testable'] and \
               a.days_since_exposure <= self.Testing.tests[test_type]['time_testable']:
                if self.verbosity > 1:
                    print('{} {} sent positive sample'.format(a.type, a.ID))
                a.sample = 'positive'
                self.positive_tests[test_type][a.type] += 1

            # track the undetected infections to assess how important they are
            # for infection spread
            else:
                if self.verbosity > 1:
                    print(
                        '{} {} sent negative sample (even though infectious)'.
                        format(a.type, a.ID))
                a.sample = 'negative'
                self.undetected_infections += 1

        else:
            if self.verbosity > 1:
                print('{} {} sent negative sample'.format(a.type, a.ID))
            a.sample = 'negative'

        # for same-day testing, immediately act on the results of the test
        if a.days_since_tested >= self.Testing.tests[test_type][
                'time_until_test_result']:
            a.act_on_test_result()

    def screen_agents(self, agent_group, test_type, screen_type):
        # only test agents that have not been tested already in this simulation
        # step and that are not already known positive cases

        if self.verbosity > 0:
            print('initiating {} {} screen'\
                                .format(screen_type, agent_group))

        untested_agents = [
            a for a in self.schedule.agents
            if (a.tested == False and a.known_positive == False
                and a.type == agent_group)
        ]

        if len(untested_agents) > 0:
            self.screened_agents[screen_type][agent_group] = True
            self.days_since_last_agent_screen[agent_group] = 0

            # only test agents if they participate in voluntary testing
            if screen_type == 'preventive':
                for a in untested_agents:
                    if a.voluntary_testing:
                        self.test_agent(a, test_type)
                    else:
                        if self.verbosity > 1:
                            print('not testing {} {}, not participating in voluntary testing'\
                                .format(agent_group, a.ID))
            else:
                for a in untested_agents:
                    self.test_agent(a, test_type)

            if self.verbosity > 0:
                print()
        else:
            if self.verbosity > 0:
                print(
                    'no agents tested because all agents have already been tested'
                )

    # the type of the test used in the pending test result is stored in the
    # variable pending_test

    def collect_test_results(self):
        agents_with_test_results = [
            a for a in self.schedule.agents
            if (a.pending_test and a.days_since_tested >= self.Testing.tests[
                a.pending_test]['time_until_test_result'])
        ]

        return agents_with_test_results

    def trace_contacts(self, a):
        if a.quarantined == False:
            a.quarantined = True
            a.quarantine_start = self.Nstep

            if self.verbosity > 0:
                print('qurantined {} {}'.format(a.type, a.ID))

        # find all agents that share edges with the agent
        # that are classified as K1 contact types in the testing
        # strategy
        K1_contacts = [
            e[1] for e in self.G.edges(a.ID, data=True)
            if e[2]['contact_type'] in self.Testing.K1_contact_types
        ]
        K1_contacts = [a for a in self.schedule.agents if a.ID in K1_contacts]

        for K1_contact in K1_contacts:
            if self.verbosity > 0:
                print('quarantined {} {} (K1 contact of {} {})'.format(
                    K1_contact.type, K1_contact.ID, a.type, a.ID))
            K1_contact.quarantined = True
            K1_contact.quarantine_start = self.Nstep

    def test_symptomatic_agents(self):
        # find symptomatic agents that have not been tested yet and are not
        # in quarantine and test them
        newly_symptomatic_agents = np.asarray([
            a for a in self.schedule.agents
            if (a.symptoms == True and a.tested == False
                and a.quarantined == False)
        ])

        for a in newly_symptomatic_agents:
            # all symptomatic agents are quarantined by default
            if self.verbosity > 0:
                print('quarantined: {} {}'.format(a.type, a.ID))
            a.quarantined = True
            a.quarantine_start = self.Nstep

            self.test_agent(a, self.Testing.diagnostic_test_type)

    def quarantine_contacts(self):
        # trace and quarantine contacts of newly positive agents
        if len(self.newly_positive_agents) > 0:
            if self.verbosity > 0:
                print('new positive test(s) from {}'.format(
                    [a.ID for a in self.newly_positive_agents]))

            # send all K1 contacts of positive agents into quarantine
            for a in self.newly_positive_agents:
                self.trace_contacts(a)

            # indicate that a screen should happen because there are new
            # positive test results
            self.new_positive_tests = True
            self.newly_positive_agents = []

        else:
            self.new_positive_tests = False

    def step(self):
        self.weekday = (self.Nstep + self.weekday_offset) % 7 + 1
        # if the connection graph is time-resloved, set the graph that is
        # used to determine connections in this step to the sub-graph corres-
        # ponding to the current day of the week
        if self.dynamic_connections:
            self.G = self.weekday_connections[self.weekday]

        if self.verbosity > 0:
            print('weekday {}'.format(self.weekday))

        if self.testing:
            for agent_type in self.agent_types:
                for screen_type in ['reactive', 'follow_up', 'preventive']:
                    self.screened_agents[screen_type][agent_type] = False

            if self.verbosity > 0:
                print('* testing and tracing *')

            self.test_symptomatic_agents()

            # collect and act on new test results
            agents_with_test_results = self.collect_test_results()
            for a in agents_with_test_results:
                a.act_on_test_result()

            self.quarantine_contacts()

            # screening:
            # a screen should take place if
            # (a) there are new positive test results
            # (b) as a follow-up screen for a screen that was initiated because
            # of new positive cases
            # (c) if there is a preventive screening policy and it is time for
            # a preventive screen in a given agent group

            # (a)
            if (self.testing == 'background' or self.testing == 'preventive')\
               and self.new_positive_tests == True:
                for agent_type in self.screening_agents:
                    self.screen_agents(agent_type,
                                       self.Testing.diagnostic_test_type,
                                       'reactive')
                    self.scheduled_follow_up_screen[agent_type] = True

            # (b)
            elif (self.testing == 'background' or self.testing == 'preventive') and \
                self.Testing.follow_up_testing_interval != None and \
                sum(list(self.scheduled_follow_up_screen.values())) > 0:
                for agent_type in self.screening_agents:
                    if self.scheduled_follow_up_screen[agent_type] and\
                       self.days_since_last_agent_screen[agent_type] >=\
                       self.Testing.follow_up_testing_interval:
                        self.screen_agents(agent_type,
                                           self.Testing.diagnostic_test_type,
                                           'follow_up')
                    else:
                        if self.verbosity > 0:
                            print('not initiating {} follow-up screen (last screen too close)'\
                                .format(agent_type))

            # (c)
            elif self.testing == 'preventive' and \
                np.any(list(self.Testing.screening_intervals.values())):

                for agent_type in self.screening_agents:
                    interval = self.Testing.screening_intervals[agent_type]
                    assert interval in [7, 3, 2, None], \
                        'testing interval {} for agent type {} not supported!'\
                        .format(interval, agent_type)

                    # (c.1) testing every 7 days = testing on Mondays
                    if interval == 7 and self.weekday == 1:
                        self.screen_agents(agent_type,
                            self.Testing.preventive_screening_test_type,\
                             'preventive')
                    # (c.2) testing every 3 days = testing on Mo & Turs
                    elif interval == 3 and self.weekday in [1, 4]:
                        self.screen_agents(agent_type,
                        self.Testing.preventive_screening_test_type,\
                         'preventive')
                    # (c.3) testing every 2 days = testing on Mo, Wed & Fri
                    elif interval == 2 and self.weekday in [1, 3, 5]:
                        self.screen_agents(agent_type,
                        self.Testing.preventive_screening_test_type,\
                         'preventive')
                    # No interval specified = no testing, even if testing
                    # mode == preventive
                    elif interval == None:
                        pass
                    else:
                        if self.verbosity > 0:
                            print('not initiating {} preventive screen (wrong weekday)'\
                                    .format(agent_type))
            else:
                # do nothing
                pass

            for agent_type in self.agent_types:
                if not (self.screened_agents['reactive'][agent_type] or \
                        self.screened_agents['follow_up'][agent_type] or \
                        self.screened_agents['preventive'][agent_type]):
                    self.days_since_last_agent_screen[agent_type] += 1

        if self.verbosity > 0: print('* agent interaction *')
        self.datacollector.collect(self)
        self.schedule.step()
        self.Nstep += 1
Example #41
0
    def __init__(self, diffusivity, timestep, filename, grid_pickle=None):
        '''
        LanguageModels contain LanguageAgents and other objects to run the model.
        Args:
            diffusivity:
            filename:
            grid_pickle:
        '''
        super().__init__()
        self.num_agents = 0
        self.grid = NeighborList(neighborhood_size=8, loadpickle=grid_pickle)

        self.schedule = SimultaneousActivation(self)
        self.diffusion = np.array(diffusivity)
        self.pop_data = self.read_file(filename)
        self.agent_pop = {}
        self.timestep = timestep

        # for loc in self.pop_data.loc[:]['location_id']:
        for row in self.pop_data.itertuples(index=True):
            # print('row: ' + str(row))

            # read in population data
            self.agent_pop.update({int(row[1]): [int(x) for x in row[6:]]})
            # print(self.agent_pop[row[1]])

            self.num_agents += 1
            # Create agents, add them to scheduler
            if float(row[11]) == 0:
                a = LanguageAgent(self, str(row[2]), int(row[1]), [0, 1])
            else:
                a = LanguageAgent(self, str(row[2]), int(row[1]),
                                  [float(row[5]), 1 - (float(row[5]))])

            self.schedule.add(a)

            # add the agent at position (x,y)
            # print('lat: ' + str(self.pop_data.loc[idx]['latitude']))
            # print('long ' + str(self.pop_data.loc[idx]['longitude']))
            print('id:' + str(a.unique_id))
            self.grid.add_agent(
                (float(self.pop_data.loc[a.unique_id - 1]['latitude']),
                 float(self.pop_data.loc[a.unique_id - 1]['longitude'])), a)
            # print('added')

        if grid_pickle is None:
            self.grid.calc_neighbors()

        self.datacollector = DataCollector(
            model_reporters={},
            agent_reporters={
                "pop": lambda x: x.population,
                "p_p_german": lambda x: x.p_probability[0],
                "p_p_slovene": lambda x: x.p_probability[1],
                "p_german": lambda x: x.probability[0],
                "p_slovene": lambda x: x.probability[1],
                "p_diff":
                lambda x: np.sum(np.abs(x.probability - x.p_probability)),
                "lat": lambda x: x.pos[0],
                "long": lambda x: x.pos[1]
            })
Example #42
0
    def __init__(self, G,
        verbosity = 0,
        base_transmission_risk = 0.05,
        testing='diagnostic',
        exposure_duration = [5.0, 1.9],
        time_until_symptoms = [6.4, 0.8],
        infection_duration = [10.91, 3.95],
        quarantine_duration = 10,
        subclinical_modifier = 0.6,
        infection_risk_contact_type_weights = {
            'very_far': 0.1,
            'far': 0.25,
            'intermediate': 0.5,
            'close': 1},
        K1_contact_types = ['close'],
        diagnostic_test_type = 'one_day_PCR',
        preventive_screening_test_type = 'same_day_antigen',
        follow_up_testing_interval = None,
        liberating_testing = False,
        index_case = 'teacher',
        agent_types = {
            'teacher':      {'screening_interval': None,
                             'index_probability': 0,
                             'mask':False},
            'student':      {'screening_interval': None,
                             'index_probability': 0,
                             'mask':False},
            'family_member':{'screening_interval': None,
                             'index_probability': 0,
                             'mask':False}},
        age_transmission_risk_discount = \
             {'slope':-0.02,
              'intercept':1},
        age_symptom_discount = \
             {'slope':-0.02545,
              'intercept':0.854545},
        mask_filter_efficiency = {'exhale':0, 'inhale':0},
        transmission_risk_ventilation_modifier = 0,
        seed = None):

        # mesa models already implement fixed seeds through their own random
        # number generations. Sadly, we need to use the Weibull distribution
        # here, which is not implemented in mesa's random number generation
        # module. Therefore, we need to initialize the numpy random number
        # generator with the given seed as well
        if seed != None:
            np.random.seed(seed)

        # sets the (daily) transmission risk for a household contact without
        # any precautions. Target infection ratios are taken from literature
        # and the value of the base_transmission_risk is calibrated such that
        # the simulation produces the correct infection ratios in a household
        # setting with the given distributions for epidemiological parameters
        # of agents
        self.base_transmission_risk = base_transmission_risk
        # sets the level of detail of text output to stdout (0 = no output)
        self.verbosity = check_positive_int(verbosity)
        # flag to turn off the testing & tracing strategy
        self.testing = check_testing(testing)
        self.running = True  # needed for the batch runner implemented by mesa
        # set the interaction mode to simultaneous activation
        self.schedule = SimultaneousActivation(self)

        # internal step counter used to launch screening tests
        self.Nstep = 0

        # since we may have weekday-specific contact networks, we need
        # to keep track of the day of the week. Since the index case
        # per default is introduced at step 0 in index case mode, we
        # need to offset the starting weekday by a random number of weekdays
        # to prevent artifacts from always starting on the same day of the week

        self.weekday_offset = self.random.randint(1, 8)
        self.weekday = self.Nstep + self.weekday_offset

        ## epidemiological parameters: can be either a single integer or the
        # mean and standard deviation of a distribution
        self.epi_params = {}
        # counter to track the number of pathological parameter combinations
        # that had to be re-rolled (only here for debugging and control reasons)
        self.param_rerolls = 0

        for param, param_name in zip(
            [exposure_duration, time_until_symptoms, infection_duration],
            ['exposure_duration', 'time_until_symptoms', 'infection_duration'
             ]):

            if isinstance(param, int):
                self.epi_params[param_name] = check_positive_int(param)

            elif isinstance(param, list) and len(param) == 2:

                mu = check_positive(param[0])
                var = check_positive(param[1]**2)
                shape = root_scalar(get_weibull_shape,
                                    args=(mu, var),
                                    method='toms748',
                                    bracket=[0.2, 500]).root
                scale = get_weibull_scale(mu, shape)

                self.epi_params[param_name] = [shape, scale]
            else:
                print('{} format not recognized, should be either a single '+\
                  'int or a tuple of two positive numbers'.format(param_name))

        # duration of quarantine
        self.quarantine_duration = check_positive_int(quarantine_duration)

        self.infection_risk_area_weights = check_contact_type_dict(
            infection_risk_contact_type_weights)

        # modifier for infectiosness for asymptomatic cases
        self.subclinical_modifier = check_positive(subclinical_modifier)
        # modifiers for the infection risk, depending on contact type
        self.infection_risk_contact_type_weights = infection_risk_contact_type_weights

        # discounts for age-dependent transmission and reception risks and
        # symptom probabilities
        self.age_transmission_risk_discount = \
            check_discount(age_transmission_risk_discount)
        self.age_symptom_discount = \
            check_discount(age_symptom_discount)

        self.mask_filter_efficiency = mask_filter_efficiency
        self.transmission_risk_ventilation_modifier = \
            transmission_risk_ventilation_modifier

        ## agents and their interactions
        # interaction graph of agents
        self.G = check_graph(G)
        # add weights as edge attributes so they can be visualised easily
        if type(self.G) == nx.MultiGraph:
            for (u, v, key, contact_type) in self.G.edges(keys=True,
                                                          data='contact_type'):
                self.G[u][v][key]['weight'] = \
                    self.infection_risk_contact_type_weights[contact_type]
        else:
            for e in G.edges(data=True):
                G[e[0]][e[1]]['weight'] = self.infection_risk_contact_type_weights\
                 [G[e[0]][e[1]]['contact_type']]

        # extract the different agent types from the contact graph
        self.agent_types = list(agent_types.keys())
        # dictionary of available agent classes with agent types and classes
        self.agent_classes = {}
        if 'resident' in agent_types:
            from scseirx.agent_resident import resident
            self.agent_classes['resident'] = resident
        if 'employee' in agent_types:
            from scseirx.agent_employee import employee
            self.agent_classes['employee'] = employee
        if 'student' in agent_types:
            from scseirx.agent_student import student
            self.agent_classes['student'] = student
        if 'teacher' in agent_types:
            from scseirx.agent_teacher import teacher
            self.agent_classes['teacher'] = teacher
        if 'family_member' in agent_types:
            from scseirx.agent_family_member import family_member
            self.agent_classes['family_member'] = family_member

        ## set agent characteristics for all agent groups
        # list of agent characteristics
        params = [
            'screening_interval', 'index_probability', 'mask',
            'voluntary_testing_rate'
        ]

        # default values that are used in case a characteristic is not specified
        # for an agent group
        defaults = {
            'screening_interval': None,
            'index_probability': 0,
            'mask': False,
            'voluntary_testing_rate': 1
        }

        # sanity checks that are applied to parameters passed to the class
        # constructor to make sure they conform to model expectations
        check_funcs = [
            check_positive_int, check_probability, check_bool,
            check_probability
        ]

        # member dicts that store the parameter values for each agent group
        self.screening_intervals = {}
        self.index_probabilities = {}
        self.masks = {}
        self.voluntary_testing_rates = {}

        param_dicts = [
            self.screening_intervals, self.index_probabilities, self.masks,
            self.voluntary_testing_rates
        ]

        # iterate over all possible agent parameters and agent groups: set the
        # respective value to the value passed through the constructor or to
        # the default value if no value has been passed
        for param, param_dict, check_func in zip(params, param_dicts,
                                                 check_funcs):
            for at in self.agent_types:
                try:
                    param_dict.update({at: check_func(agent_types[at][param])})
                except KeyError:
                    param_dict.update({at: defaults[param]})

        # pass all parameters relevant for the testing strategy to the testing
        # class. NOTE: this separation is not a strictly necessary design
        # decision but I like to keep the parameters related to testing and
        # tracing in a separate place
        self.Testing = Testing(self, diagnostic_test_type,
                               preventive_screening_test_type,
                               check_positive_int(follow_up_testing_interval),
                               self.screening_intervals,
                               check_bool(liberating_testing),
                               check_K1_contact_types(K1_contact_types),
                               verbosity)

        # specifies either continuous probability for index cases in agent
        # groups based on the 'index_probability' for each agent group, or a
        # single (randomly chosen) index case in the passed agent group
        self.index_case = check_index_case(index_case, self.agent_types)

        self.num_agents = {}

        ## add agents
        # extract the agent nodes from the graph and add them to the scheduler
        for agent_type in self.agent_types:
            IDs = [x for x, y in G.nodes(data=True) if y['type'] == agent_type]
            self.num_agents.update({agent_type: len(IDs)})

            # get the agent locations (units) from the graph node attributes
            units = [self.G.nodes[ID]['unit'] for ID in IDs]
            for ID, unit in zip(IDs, units):

                tmp_epi_params = {}
                # for each of the three epidemiological parameters, check if
                # the parameter is an integer (if yes, pass it directly to the
                # agent constructor), or if it is specified by the shape and
                # scale parameters of a Weibull distribution. In the latter
                # case, draw a new number for every agent from the distribution
                # NOTE: parameters drawn from the distribution are rounded to
                # the nearest integer
                while True:
                    for param_name, param in self.epi_params.items():
                        if isinstance(param, int):
                            tmp_epi_params[param_name] = param

                        else:
                            tmp_epi_params[param_name] = \
                                round(weibull_two_param(param[0], param[1]))

                    if tmp_epi_params['exposure_duration'] > 0 and \
                       tmp_epi_params['time_until_symptoms'] >= \
                       tmp_epi_params['exposure_duration'] and\
                       tmp_epi_params['infection_duration'] > \
                       tmp_epi_params['exposure_duration']:
                        break
                    else:
                        self.param_rerolls += 1
                        if verbosity > 1:
                            print('pathological epi-param case found!')
                            print(tmp_epi_params)

                # check if the agent participates in voluntary testing
                p = self.voluntary_testing_rates[agent_type]
                voluntary_testing = np.random.choice([True, False],
                                                     p=[p, 1 - p])

                a = self.agent_classes[agent_type](
                    ID, unit, self, tmp_epi_params['exposure_duration'],
                    tmp_epi_params['time_until_symptoms'],
                    tmp_epi_params['infection_duration'], voluntary_testing,
                    verbosity)
                self.schedule.add(a)

# infect the first agent in single index case mode
        if self.index_case != 'continuous':
            infection_targets = [
                a for a in self.schedule.agents if a.type == index_case
            ]
            # pick a random agent to infect in the selected agent group
            target = self.random.randint(0, len(infection_targets) - 1)
            infection_targets[target].exposed = True
            if self.verbosity > 0:
                print('{} exposed: {}'.format(index_case,
                                              infection_targets[target].ID))

        # list of agents that were tested positive this turn
        self.newly_positive_agents = []
        # flag that indicates if there were new positive tests this turn
        self.new_positive_tests = False
        # dictionary of flags that indicate whether a given agent group has
        # been creened this turn
        self.screened_agents = {
            'reactive': {agent_type: False
                         for agent_type in self.agent_types},
            'follow_up':
            {agent_type: False
             for agent_type in self.agent_types},
            'preventive':
            {agent_type: False
             for agent_type in self.agent_types}
        }

        # dictionary of counters that count the days since a given agent group
        # was screened. Initialized differently for different index case modes
        if (self.index_case == 'continuous') or \
          (not np.any(list(self.Testing.screening_intervals.values()))):
            self.days_since_last_agent_screen = {
                agent_type: 0
                for agent_type in self.agent_types
            }
        # NOTE: if we initialize these variables with 0 in the case of a single
        # index case, we introduce a bias since in 'single index case mode' the
        # first index case will always become exposed in step 0. To realize
        # random states of the preventive sceening procedure with respect to the
        # incidence of the index case, we have to randomly pick the days since
        # the last screen for the agent group from which the index case is
        else:
            self.days_since_last_agent_screen = {}
            for agent_type in self.agent_types:
                if self.Testing.screening_intervals[agent_type] != None:
                    self.days_since_last_agent_screen.update({
                        agent_type:
                        self.random.choice(
                            range(
                                0,
                                self.Testing.screening_intervals[agent_type] +
                                1))
                    })
                else:
                    self.days_since_last_agent_screen.update({agent_type: 0})

        # dictionary of flags that indicates whether a follow-up screen for a
        # given agent group is scheduled
        self.scheduled_follow_up_screen = {
            agent_type: False
            for agent_type in self.agent_types
        }

        # counters
        self.number_of_diagnostic_tests = 0
        self.number_of_preventive_screening_tests = 0
        self.positive_tests = {
            self.Testing.preventive_screening_test_type:
            {agent_type: 0
             for agent_type in self.agent_types},
            self.Testing.diagnostic_test_type:
            {agent_type: 0
             for agent_type in self.agent_types}
        }

        self.undetected_infections = 0
        self.predetected_infections = 0
        self.pending_test_infections = 0
        self.quarantine_counters = {
            agent_type: 0
            for agent_type in agent_types.keys()
        }
        self.false_negative = 0

        # data collectors to save population counts and agent states every
        # time step
        self.datacollector = DataCollector(
            model_reporters=
             {
             'N_diagnostic_tests':get_N_diagnostic_tests,
                'N_preventive_screening_tests':get_N_preventive_screening_tests,
                'diagnostic_test_detected_infections_student':\
                        get_diagnostic_test_detected_infections_student,
                'diagnostic_test_detected_infections_teacher':\
                        get_diagnostic_test_detected_infections_teacher,
                'diagnostic_test_detected_infections_family_member':\
                        get_diagnostic_test_detected_infections_family_member,
                'preventive_test_detected_infections_student':\
                        get_preventive_test_detected_infections_student,
                'preventive_test_detected_infections_teacher':\
                        get_preventive_test_detected_infections_teacher,
                'preventive_test_detected_infections_family_member':\
                        get_preventive_test_detected_infections_family_member,
                'undetected_infections':get_undetected_infections,
                'predetected_infections':get_predetected_infections,
                'pending_test_infections':get_pending_test_infections
                },

            agent_reporters=
             {
             'infection_state': get_infection_state,
                'quarantine_state': get_quarantine_state
                })
Example #43
0
    def __init__(self, width, height):

        # Model attributes initialization
        self.workers_number = 10
        self.agents = []
        self.workers = []
        self.average_stress = 0
        self.running = True

        #SOBA
        configuration.settings.init()
        configuration.defineOccupancy.init()
        configuration.defineMap.init()

        self.clock = Time()

        #Vars of control
        self.num_occupants = 0
        self.day = self.clock.day
        self.NStep = 0
        self.placeByStateByTypeAgent = {}
        self.agentsWorkingByStep = []
        self.agentsIn = 0

        # Schedule
        self.schedule = BaseScheduler(self)
        self.grid = MultiGrid(width, height, False)

        #Create the map
        self.createRooms()
        self.setMap(width, height)
        self.createDoors()
        self.createWalls()
        #Create agents
        self.setAgents()

        # Create timer agent
        self.timer = TimeAgent(len(self.agents), self)
        self.schedule.add(self.timer)
        self.agents.append(self.timer)

        # Create sensor agent
        self.sensor = SensorAgent(len(self.agents), self)
        self.schedule.add(self.sensor)
        self.agents.append(self.sensor)
        '''
        # Create workers agents
        for i in range(self.workers_number):
            worker = WorkerAgent(i+len(self.agents), self)
            self.schedule.add(worker)
            self.workers.append(worker)
        '''

        # Create data collectors
        self.model_collector = DataCollector(
            model_reporters={"Average Stress": lambda a: a.average_stress})
        self.worker_collector = WorkerCollector(
            agent_reporters={
                "Stress": lambda a: a.stress,
                "Event Stress": lambda a: a.event_stress,
                "Time Pressure": lambda a: a.time_pressure,
                "Effective Fatigue": lambda a: a.effective_fatigue,
                "Productivity": lambda a: a.productivity,
                'Emails read': lambda a: a.emails_read,
                'Pending tasks': lambda a: len(a.tasks),
                'Overtime hours': lambda a: a.overtime_hours,
                'Rest at work hours': lambda a: a.rest_at_work_hours,
                'Tasks completed': lambda a: a.tasks_completed
            })
        self.sensor_collector = SensorCollector(
            agent_reporters={
                "Temperature": lambda a: a.wbgt,
                "Noise": lambda a: a.noise,
                "Luminosity": lambda a: a.luminosity
            })
        self.time_collector = TimeCollector(agent_reporters={
            "Day": lambda a: a.days,
            "Time": lambda a: a.clock
        })
Example #44
0
class SOMENModel(Model):
    def __init__(self, width, height):

        # Model attributes initialization
        self.workers_number = 10
        self.agents = []
        self.workers = []
        self.average_stress = 0
        self.running = True

        #SOBA
        configuration.settings.init()
        configuration.defineOccupancy.init()
        configuration.defineMap.init()

        self.clock = Time()

        #Vars of control
        self.num_occupants = 0
        self.day = self.clock.day
        self.NStep = 0
        self.placeByStateByTypeAgent = {}
        self.agentsWorkingByStep = []
        self.agentsIn = 0

        # Schedule
        self.schedule = BaseScheduler(self)
        self.grid = MultiGrid(width, height, False)

        #Create the map
        self.createRooms()
        self.setMap(width, height)
        self.createDoors()
        self.createWalls()
        #Create agents
        self.setAgents()

        # Create timer agent
        self.timer = TimeAgent(len(self.agents), self)
        self.schedule.add(self.timer)
        self.agents.append(self.timer)

        # Create sensor agent
        self.sensor = SensorAgent(len(self.agents), self)
        self.schedule.add(self.sensor)
        self.agents.append(self.sensor)
        '''
        # Create workers agents
        for i in range(self.workers_number):
            worker = WorkerAgent(i+len(self.agents), self)
            self.schedule.add(worker)
            self.workers.append(worker)
        '''

        # Create data collectors
        self.model_collector = DataCollector(
            model_reporters={"Average Stress": lambda a: a.average_stress})
        self.worker_collector = WorkerCollector(
            agent_reporters={
                "Stress": lambda a: a.stress,
                "Event Stress": lambda a: a.event_stress,
                "Time Pressure": lambda a: a.time_pressure,
                "Effective Fatigue": lambda a: a.effective_fatigue,
                "Productivity": lambda a: a.productivity,
                'Emails read': lambda a: a.emails_read,
                'Pending tasks': lambda a: len(a.tasks),
                'Overtime hours': lambda a: a.overtime_hours,
                'Rest at work hours': lambda a: a.rest_at_work_hours,
                'Tasks completed': lambda a: a.tasks_completed
            })
        self.sensor_collector = SensorCollector(
            agent_reporters={
                "Temperature": lambda a: a.wbgt,
                "Noise": lambda a: a.noise,
                "Luminosity": lambda a: a.luminosity
            })
        self.time_collector = TimeCollector(agent_reporters={
            "Day": lambda a: a.days,
            "Time": lambda a: a.clock
        })

    #SOBA
    def setAgents(self):

        self.lights = []
        id_light = 0
        for room in self.rooms:
            if room.typeRoom != 'out' and room.light == False:
                light = Light(id_light, self, room)
                self.lights.append(light)
                id_light = id_light + 1
                room.light = light
                for room2 in self.rooms:
                    if room.name.split(r".")[0] == room2.name.split(r".")[0]:
                        room2.light = light

        # Height and Width
        height = self.grid.height
        width = self.grid.width

        # CREATE AGENTS

        self.agents = []
        # Create occupants
        for n_type_occupants in configuration.defineOccupancy.occupancy_json:
            self.placeByStateByTypeAgent[
                n_type_occupants['type']] = n_type_occupants['states']
            n_agents = n_type_occupants['N']
            for i in range(0, n_agents):
                a = WorkerAgent(i + len(self.agents) + 1000, self,
                                n_type_occupants)
                self.workers.append(a)
                self.schedule.add(a)
                self.grid.place_agent(a, self.outBuilding.pos)
                self.pushAgentRoom(a, self.outBuilding.pos)
                self.num_occupants = self.num_occupants + 1

        self.schedule.add(self.clock)
        for light in self.lights:
            self.schedule.add(light)

    def isConected(self, pos):
        nextRoom = False
        for room in self.rooms:
            if room.pos == pos:
                nextRoom = room
        if nextRoom == False:
            return False
        for x in range(0, width):
            for y in range(0, height):
                self.pos_out_of_map.append(x, y)
        for room in self.rooms:
            self.pos_out_of_map.remove(room.pos)

    def createRooms(self):
        rooms = configuration.defineMap.rooms_json
        self.rooms = []
        for room in rooms:
            newRoom = 0
            name = room['name']
            typeRoom = room['type']
            if typeRoom != 'out':
                conectedTo = room.get('conectedTo')
                entrance = room.get('entrance')
                measures = room['measures']
                dx = measures['dx']
                dy = measures['dy']
                newRoom = Room(name, typeRoom, conectedTo, dx, dy)
                newRoom.entrance = entrance
            else:
                newRoom = Room(
                    name,
                    typeRoom,
                    None,
                    0,
                    0,
                )
                self.outBuilding = newRoom
            self.rooms.append(newRoom)
        for room1 in self.rooms:
            if room1.conectedTo is not None:
                for otherRooms in list(room1.conectedTo.values()):
                    for room2 in self.rooms:
                        if room2.name == otherRooms:
                            room1.roomsConected.append(room2)
                            room2.roomsConected.append(room1)
        for room in self.rooms:
            room.roomsConected = list(set(room.roomsConected))
        sameRoom = {}
        for room in self.rooms:
            if sameRoom.get(room.name.split(r".")[0]) is None:
                sameRoom[room.name.split(r".")[0]] = 1
            else:
                sameRoom[room.name.split(r".")
                         [0]] = sameRoom[room.name.split(r".")[0]] + 1

    def setMap(self, width, height):
        rooms_noPos = self.rooms
        rooms_using = []
        rooms_used = []
        for room in self.rooms:
            if room.entrance is not None:
                room.pos = (int(1), 1)
                rooms_using.append(room)
                rooms_used.append(room)
                rooms_noPos.remove(room)
                break
        while len(rooms_noPos) > 0:
            for roomC in rooms_using:
                xc, yc = roomC.pos
                rooms_conected = roomC.conectedTo
                rooms_using.remove(roomC)
                if rooms_conected is not None:
                    orientations = list(rooms_conected.keys())
                    for orientation in orientations:
                        if orientation == 'R':
                            for room in rooms_noPos:
                                if room.name == rooms_conected['R']:
                                    room.pos = (int(xc + 1), yc)
                                    rooms_noPos.remove(room)
                                    rooms_used.append(room)
                                    rooms_using.append(room)
                        elif orientation == 'U':
                            for room in rooms_noPos:
                                if room.name == rooms_conected['U']:
                                    room.pos = (xc, int(yc + 1))
                                    rooms_noPos.remove(room)
                                    rooms_used.append(room)
                                    rooms_using.append(room)
                        elif orientation == 'D':
                            for room in rooms_noPos:
                                if room.name == rooms_conected['D']:
                                    room.pos = (xc, int(yc - 1))
                                    rooms_noPos.remove(room)
                                    rooms_used.append(room)
                                    rooms_using.append(room)
                        elif orientation == 'L':
                            for room in rooms_noPos:
                                if room.name == rooms_conected['L']:
                                    room.pos = (int(xc - 1), yc)
                                    rooms_noPos.remove(room)
                                    rooms_used.append(room)
                                    rooms_using.append(room)
                else:
                    pass
        self.rooms = rooms_used

    def createDoors(self):
        self.doors = []
        for roomC in self.rooms:
            roomsConected = roomC.roomsConected
            for room in roomsConected:
                door_created = False
                same_corridor = False
                if room.name != roomC.name:
                    for door in self.doors:
                        if (door.room1.name == roomC.name
                                and door.room2.name == room.name) or (
                                    door.room2.name == roomC.name
                                    and door.room1.name == room.name):
                            door_created = True
                        if room.name.split(r".")[0] == roomC.name.split(
                                r".")[0]:
                            same_corridor = True
                    if door_created == False and same_corridor == False:
                        d = Door(roomC, room)
                        self.doors.append(d)
                        room.doors.append(d)
                        roomC.doors.append(d)

    def createWalls(self):
        for room in self.rooms:
            if room.typeRoom != 'out':
                walls = []
                xr, yr = room.pos
                roomA = self.getRoom((xr, yr + 1))
                if roomA != False:
                    if roomA.name.split(r".")[0] == room.name.split(r".")[0]:
                        pass
                    else:
                        wall = Wall(room, roomA)
                        walls.append(wall)
                else:
                    wall = Wall(room)
                    walls.append(wall)
                roomB = self.getRoom((xr, yr - 1))
                if roomB != False:
                    if roomB.name.split(r".")[0] == room.name.split(r".")[0]:
                        pass
                    else:
                        wall = Wall(room, roomB)
                        walls.append(wall)
                else:
                    wall = Wall(room)
                    walls.append(wall)
                roomC = self.getRoom((xr + 1, yr))
                if roomC != False:
                    if roomC.name.split(r".")[0] == room.name.split(r".")[0]:
                        pass
                    else:
                        wall = Wall(room, roomC)
                        walls.append(wall)
                else:
                    wall = Wall(room)
                    walls.append(wall)
                roomD = self.getRoom((xr - 1, yr))
                if roomD != False:
                    if roomD.name.split(r".")[0] == room.name.split(r".")[0]:
                        pass
                    else:
                        wall = Wall(room, roomD)
                        walls.append(wall)
                else:
                    wall = Wall(room)
                    walls.append(wall)

                room.walls = walls

    def getPosState(self, name, typeA):
        placeByStateByTypeAgent = self.placeByStateByTypeAgent
        n = 0
        for state in self.placeByStateByTypeAgent[typeA]:
            if state.get('name') == name:
                pos1 = state.get('position')
                if isinstance(pos1, dict):
                    for k, v in pos1.items():
                        if v > 0:
                            placeByStateByTypeAgent[typeA][n]['position'][
                                k] = v - 1
                            self.placeByStateByTypeAgent = placeByStateByTypeAgent
                            return k
                    return list(pos1.keys())[-1]
                else:
                    return pos1
            n = n + 1

    def thereIsClosedDoor(self, beforePos, nextPos):
        oldRoom = False
        newRoom = False
        for room in rooms:
            if room.pos == beforePos:
                oldRoom = room
            if room.pos == nextPos:
                newRoom = room
        for door in self.doors:
            if (door.room1.name == oldRoom.name and door.room2.name
                    == newRoom.name) or (door.room2.name == oldRoom.name
                                         and door.room1.name == newRoom.name):
                if door.state == False:
                    return True
        return False

    def thereIsOccupant(self, pos):
        possible_occupant = self.grid.get_cell_list_contents([pos])
        if (len(possible_occupant) > 0):
            for occupant in possible_occupant:
                if isinstance(occupant, WorkerAgent):
                    return True
        return False

    def ThereIsOtherOccupantInRoom(self, room, agent):
        for roomAux in self.rooms:
            possible_occupant = []
            if roomAux.name.split(r".")[0] == room.name.split(r".")[0]:
                possible_occupant = self.grid.get_cell_list_contents(
                    roomAux.pos)
            for occupant in possible_occupant:
                if isinstance(occupant, WorkerAgent) and occupant != agent:
                    return True
        return False

    def ThereIsSomeOccupantInRoom(self, room):
        for roomAux in self.rooms:
            possible_occupant = []
            if roomAux.name.split(r".")[0] == room.name.split(r".")[0]:
                possible_occupant = self.grid.get_cell_list_contents(
                    roomAux.pos)
            for occupant in possible_occupant:
                if isinstance(occupant, WorkerAgent):
                    return True
        return False

    def thereIsOccupantInRoom(self, room, agent):
        for roomAux in self.rooms:
            possible_occupant = []
            if roomAux.name.split(r".")[0] == room.name.split(r".")[0]:
                possible_occupant = self.grid.get_cell_list_contents(
                    roomAux.pos)
            for occupant in possible_occupant:
                if isinstance(occupant, WorkerAgent) and occupant == agent:
                    return True
        return False

    def getRoom(self, pos):
        for room in self.rooms:
            if room.pos == pos:
                return room
        return False

    def pushAgentRoom(self, agent, pos):
        room = self.getRoom(pos)
        room.agentsInRoom.append(agent)

    def popAgentRoom(self, agent, pos):
        room = self.getRoom(pos)
        room.agentsInRoom.remove(agent)

    def openDoor(self, agent, room1, room2):
        for door in self.doors:
            if ((door.room1 == room1 and door.room2 == room2)
                    or (door.room1 == room2 and door.room2 == room1)):
                door.state = False

    def closeDoor(self, agent, room1, room2):
        numb = random.randint(0, 10)
        for door in self.doors:
            if ((door.room1 == room1 and door.room2 == room2)
                    or (door.room1 == room2 and door.room2 == room1)):
                if 7 >= numb:
                    door.state = False
                else:
                    door.state = True

    def getMatrix(self, agent):
        new_matrix = configuration.defineOccupancy.returnMatrix(
            agent, self.clock.clock)
        agent.markov_matrix = new_matrix

    def getTimeInState(self, agent):
        matrix_time_in_state = configuration.defineOccupancy.getTimeInState(
            agent, self.clock.clock)
        return matrix_time_in_state

    def sobaStep(self):
        aw = 0
        for agent in self.agents:
            if agent.state == 'working in my workplace':
                aw = aw + 1
        self.agentsWorkingByStep.append(aw)
        self.schedule.step()

        if (self.clock.day > self.day):
            self.day = self.day + 1
        self.NStep = self.NStep + 1

        if self.clock.clock > 17:
            model.ramenScript.generateJSON()
            while (True):
                pass

    def step(self):

        self.sobaStep()

        if self.timer.new_day:
            self.addTasks()
            self.createEmailsDistribution()

        self.average_stress = sum(
            worker.stress for worker in self.workers) / len(self.workers)

        if self.timer.new_hour:
            self.worker_collector.collect(self)
            self.sensor_collector.collect(self)
            self.time_collector.collect(self)
            self.model_collector.collect(self)

    def addTasks(self):
        ''' Add tasks to workers '''

        # Get task distribution params
        mu, sigma = workload_settings.tasks_arriving_distribution_params
        tasks_arriving_distribution = np.random.normal(
            mu, sigma, self.workers_number * 10)

        for worker in self.workers:

            # Get number of tasks to add
            tasks_number = math.floor(
                abs(tasks_arriving_distribution[random.randint(
                    0, 10 * self.workers_number - 1)]))
            worker.tasks_completed = 0

            # Add tasks
            for i in range(tasks_number):
                worker.addTask(Task())

            worker.calculateAverageDailyTasks(self.timer.days)
            worker.calculateEventStress(tasks_number)

            # worker.printTasksNumber()
            # worker.printAverageDailyTasks()
            # worker.printEventStress()

    def createEmailsDistribution(self):
        '''Create emails distribution'''
        # Get emails distribution
        mu, sigma = email_settings.emails_read_distribution_params
        emails_read_distribution = np.random.normal(mu, sigma,
                                                    self.workers_number * 10)

        for worker in self.workers:

            emails_received = math.floor(
                abs(emails_read_distribution[random.randint(
                    0, 10 * self.workers_number - 1)]))
            emails_distribution_over_time = np.random.choice(
                [0, 1],
                size=(480, ),
                p=[(480 - emails_received) / 480, emails_received / 480])
            worker.emails_read = 0
            worker.email_read_distribution_over_time = emails_distribution_over_time
Example #45
0
    def __init__(self, N, width, height):
        self.num_agents = N
        self.width = width
        self.height = height
        self.grid = MultiGrid(height, width, False)  #non toroidal grid
        self.schedule = SimultaneousActivation(self)
        self.datacollector = DataCollector(
            model_reporters={"Coverage": compute_coverage},
            agent_reporters={"Wealth": "wealth"})
        # Create agents
        self.coveredArea = []
        self.interactionCount = 0
        self.interactionRateAverage = 0
        self.coveragePercentage = 0
        self.coveragePercentageAverage = 0

        #for ordered walk
        self.orientation = np.ones((self.height, self.width))
        self.orientation[:1] = np.full((1, self.width), 2)
        self.orientation[:self.height, self.width - 1:] = np.full(
            (self.height, 1), 3)
        self.orientation[self.height - 1:, ] = np.full((1, self.width), 4)
        self.orientation[:self.height, :1] = np.full((self.height, 1), 1)
        self.orientation[0][0] = 2

        #        distribute the agents evently
        areaNum = ceil(sqrt(self.num_agents))
        areaDistx = self.width / (sqrt(self.num_agents))
        areaDistx = floor(areaDistx)
        areaDisty = self.height / (sqrt(self.num_agents))
        areaDisty = floor(areaDisty)

        self.dtx = areaDistx
        self.dty = areaDisty

        for i in range(self.num_agents):

            xlow = (i % areaNum) * areaDistx
            xup = xlow + areaDistx - 1

            ylow = floor(i / areaNum) * areaDisty
            yup = ylow + areaDisty - 1

            x = floor((xlow + xup) / 2) + 1
            y = floor((ylow + yup) / 2) + 1

            xlow = x - 1
            xup = x + 1
            ylow = y - 1
            yup = y + 1

            #            create and add agent with id number i to the scheduler
            a = MoniAgent(i, self, xup, xlow, yup, ylow)
            self.schedule.add(a)

            #place agent at the center of its limit coor
            self.grid.place_agent(a, (x, y))
            # Add the agent to a random grid cell

#        this part is for visualization only
        self.running = True
        self.datacollector.collect(self)
Example #46
0
    def __init__(self,
                 background_opinion=Opinion.NO,
                 seeded_opinion=Opinion.YES,
                 num_people=50,
                 num_subcultures=10,
                 avg_node_degree=5,
                 initial_seed_size=3,
                 opinion_change_chance=0.4,
                 opinion_check_frequency=0.4):

        self.num_people = num_people
        self.num_subcultures = num_subcultures
        total_degrees = avg_node_degree * self.num_people
        subculture_degrees = []
        for i in range(self.num_subcultures):
            degrees_left = total_degrees - sum(subculture_degrees)
            subcultures_left = self.num_subcultures - i
            subculture_degrees.append(
                random.randrange(1, degrees_left - subcultures_left
                                 ) if subcultures_left > 1 else degrees_left)

        self.G = bipartite.configuration_model(
            [avg_node_degree] * self.num_people, subculture_degrees)
        people, subcultures = bipartite.sets(self.G)

        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)

        self.background_opinion = next(
            (opinion
             for opinion in Opinion if opinion.name == background_opinion),
            None)
        self.seeded_opinion = next(
            (opinion for opinion in Opinion if opinion.name == seeded_opinion),
            None)
        self.initial_seed_size = min(initial_seed_size,
                                     self.num_people + self.num_subcultures)
        self.opinion_change_chance = opinion_change_chance
        self.opinion_check_frequency = opinion_check_frequency

        self.datacollector = DataCollector({
            "Neutral":
            lambda model: opinion_count(model, Opinion.NEUTRAL),
            "Yes":
            lambda model: opinion_count(model, Opinion.YES),
            "No":
            lambda model: opinion_count(model, Opinion.NO)
        })

        # Create People
        for i, node in enumerate(people):
            p = Person(i, self, self.background_opinion,
                       self.opinion_change_chance,
                       self.opinion_check_frequency)
            self.schedule.add(p)
            # Add the Person to the node
            self.grid.place_agent(p, node)

        # Create SubCultures
        for i, node in enumerate(subcultures):
            s = SubCulture(i, self)
            self.schedule.add(s)
            # Add the SubCulture to the node
            self.grid.place_agent(s, node)

        # Seed some opinions
        seed = self.random.sample(subcultures, 1)[0]
        seed_network = nx.algorithms.traversal.depth_first_search.dfs_preorder_nodes(
            self.G, seed)
        for node in islice(seed_network, initial_seed_size):
            person = self.G.nodes[node]['agent'][0]
            person.opinion = self.seeded_opinion

        self.running = True
        self.datacollector.collect(self)
Example #47
0
class MoniModel(Model):
    """A simple model of an economy where agents exchange currency at random.

    All the agents begin with one unit of currency, and each time step can give
    a unit of currency to another agent. Note how, over time, this produces a
    highly skewed distribution of wealth.
    """
    def __init__(self, N, width, height):
        self.num_agents = N
        self.width = width
        self.height = height
        self.grid = MultiGrid(height, width, False)  #non toroidal grid
        self.schedule = SimultaneousActivation(self)
        self.datacollector = DataCollector(
            model_reporters={"Coverage": compute_coverage},
            agent_reporters={"Wealth": "wealth"})
        # Create agents
        self.coveredArea = []
        self.interactionCount = 0
        self.interactionRateAverage = 0
        self.coveragePercentage = 0
        self.coveragePercentageAverage = 0

        #for ordered walk
        self.orientation = np.ones((self.height, self.width))
        self.orientation[:1] = np.full((1, self.width), 2)
        self.orientation[:self.height, self.width - 1:] = np.full(
            (self.height, 1), 3)
        self.orientation[self.height - 1:, ] = np.full((1, self.width), 4)
        self.orientation[:self.height, :1] = np.full((self.height, 1), 1)
        self.orientation[0][0] = 2

        #        distribute the agents evently
        areaNum = ceil(sqrt(self.num_agents))
        areaDistx = self.width / (sqrt(self.num_agents))
        areaDistx = floor(areaDistx)
        areaDisty = self.height / (sqrt(self.num_agents))
        areaDisty = floor(areaDisty)

        self.dtx = areaDistx
        self.dty = areaDisty

        for i in range(self.num_agents):

            xlow = (i % areaNum) * areaDistx
            xup = xlow + areaDistx - 1

            ylow = floor(i / areaNum) * areaDisty
            yup = ylow + areaDisty - 1

            x = floor((xlow + xup) / 2) + 1
            y = floor((ylow + yup) / 2) + 1

            xlow = x - 1
            xup = x + 1
            ylow = y - 1
            yup = y + 1

            #            create and add agent with id number i to the scheduler
            a = MoniAgent(i, self, xup, xlow, yup, ylow)
            self.schedule.add(a)

            #place agent at the center of its limit coor
            self.grid.place_agent(a, (x, y))
            # Add the agent to a random grid cell

#        this part is for visualization only
        self.running = True
        self.datacollector.collect(self)

    def step(self):
        self.interactionCount = 0
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

        with open('reportRandomStride.csv', 'a') as reportFile:
            coverage = compute_coverage(self)
            percentage = ceil(
                10000 * coverage / self.width / self.height) / 100

            interactionRate = self.interactionCount / self.num_agents / (
                self.num_agents - 1)
            #number of interaction/possible interaction /2 for double counting
            interactionRate = ceil(10000 * interactionRate) / 100

            self.interactionRateAverage = (
                self.interactionRateAverage * (self.schedule.steps - 1) +
                interactionRate) / self.schedule.steps
            self.interactionRateAverage = ceil(
                100 * self.interactionRateAverage) / 100

            self.coveragePercentageAverage = (self.coveragePercentageAverage *
                                              (self.schedule.steps - 1) +
                                              percentage) / self.schedule.steps
            self.coveragePercentageAverage = ceil(
                100 * self.coveragePercentageAverage) / 100

            rewriter = csv.writer(reportFile,
                                  delimiter=' ',
                                  quotechar='"',
                                  quoting=csv.QUOTE_MINIMAL)
            rewriter.writerow([
                "step:", self.schedule.steps, "InteractionRate:",
                interactionRate, '%', "AvgInteractionRate",
                self.interactionRateAverage, '%', "Coverage:", coverage,
                percentage, '%', self.coveragePercentageAverage, '%'
            ])

#    def initPosTest(self)

    def run_model(self, n):
        for i in range(n):
            #            self.initPos()
            self.step()
Example #48
0
class Home(Model):
    """
    A Home Violence Simulation Model
    """

    verbose = True  # Print-monitoring
    description = 'A model for simulating the victim aggressor interaction mediated by presence of violence.'

    def __init__(self, height=40, width=40,
                 initial_families=1000,
                 metro='BRASILIA',
                 gender_stress=.8,
                 under_influence=.1,
                 has_gun=.1,
                 is_working_pct=.8,
                 chance_changing_working_status=.05,
                 pct_change_wage=.05,
                 model_scale=1000,
                 quarantine=False,
                 dissuasion=True,
                 data_year=2010):
        """
        A violence violence model of Brazilian metropolis

        """
        super().__init__()
        # Set parameters
        self.height = height
        self.width = width

        self.initial_families = initial_families
        self.metro = metro

        self.gender_stress = gender_stress
        self.under_influence = under_influence
        self.has_gun = has_gun
        self.is_working_pct = is_working_pct
        self.chance_changing_working_status = chance_changing_working_status
        self.pct_change_wage = pct_change_wage
        self.model_scale = model_scale
        self.quarantine = quarantine
        self.dissuasion = dissuasion
        self.data_year = data_year
        self.neighborhood_stress = dict()

        self.schedule = RandomActivationByBreed(self)
        self.grid = MultiGrid(self.height, self.width, torus=True)
        # Model reporters. How they work: lambda function passes model and other parameters.
        # Then another function may iterate over each 'agent in model.schedule.agents'
        # Then server is going to collect info using the keys in model_reporters dictionary
        model_reporters = {
            "Denounce": lambda m: self.count_type_citizens(m, 'denounce'),
            "Got attacked": lambda m: self.count_type_citizens(m, 'got_attacked'),
            "Females": lambda m: self.count_type_citizens(m, 'female'),
            "Stress": lambda m: self.count_stress(m)}
        self.datacollector = DataCollector(model_reporters=model_reporters)

        # Create people ---------------------------------------------------
        # Parameters to choose metropolitan region
        # More details available at input/population
        params = dict()
        params['PROCESSING_ACPS'] = [self.metro]
        params['MEMBERS_PER_FAMILY'] = 2.5
        params['INITIAL_FAMILIES'] = self.initial_families
        params['DATA_YEAR'] = self.data_year
        people, families = generator.main(params=params)
        # General random data for each individual
        n = sum([len(f) for f in families])
        working = np.random.choice([True, False], n, p=[self.is_working_pct, 1 - self.is_working_pct])
        influence = np.random.choice([True, False], n, p=[self.under_influence, 1 - self.under_influence])
        gun = np.random.choice([True, False], n, p=[self.has_gun, 1 - self.has_gun])
        i = 0
        for fam in families:
            # 1. Create a family.
            x = self.random.randrange(self.width)
            y = self.random.randrange(self.height)
            # Create a family
            family = Family(self.next_id(), self, (x, y))
            # Add family to grid
            self.grid.place_agent(family, (x, y))
            self.schedule.add(family)
            # Marriage procedures
            engaged = ['male_adult', 'female_adult']
            to_marry = list()
            # Add people to families
            for each in fam:
                person = people.loc[each]
                doe = Person(self.next_id(), self, (x, y),
                             # From IBGE's sampling
                             gender=person.gender,
                             age=person.age,
                             color=person.cor,
                             address=person.AREAP,
                             years_study=person.years_study,
                             reserve_wage=person.wage,
                             # End of sampling
                             is_working=working[i],
                             under_influence=influence[i],
                             has_gun=gun[i])
                # Marrying
                if len(engaged) > 0:
                    if person.category in engaged:
                        engaged.remove(person.category)
                        to_marry.append(doe)
                # Change position in the random list previously sampled
                i += 1
                self.grid.place_agent(doe, (x, y))
                self.schedule.add(doe)
                family.add_agent(doe)
            # 2. Marry the couple
            if len(to_marry) == 2:
                to_marry[0].assign_spouse(to_marry[1])

            # 3. Update number of family members
            for member in family.members.values():
                member.num_members_family = len(family.members)

        self.running = True
        self.datacollector.collect(self)

    def step(self):
        self.update_neighborhood_stress()
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

        # Check if step will happen at individual levels or at family levels or BOTH
        if self.verbose:
            print([self.schedule.time, self.schedule.get_breed_count(Person)])

        # New condition to stop the model
        if self.schedule.get_breed_count(Person) == 0:
            self.running = False

    def update_neighborhood_stress(self):
        # Start from scratch every step
        self.neighborhood_stress = dict()
        counter = dict()
        for agent in self.schedule.agents:
            if isinstance(agent, Family):
                self.neighborhood_stress[agent.address] = self.neighborhood_stress.get(agent.address, 0) + \
                                                          agent.context_stress
                counter[agent.address] = counter.get(agent.address, 0) + 1
        for key in self.neighborhood_stress.keys():
            self.neighborhood_stress[key] = self.neighborhood_stress[key] / counter[key]
            # print(f'This neighborhood {key} stress levels is at {self.neighborhood_stress[key]}')

    @staticmethod
    def count_type_citizens(model, condition):
        """
        Helper method to count agents by Type.
        """
        count = 0
        for agent in model.schedule.agents:
            if isinstance(agent, Person):
                if 'denounce' == condition:
                    count += agent.denounce
                elif 'got_attacked' == condition:
                    count += agent.got_attacked
                elif 'female' == condition:
                    if agent.gender == 'female':
                        if agent.age > 18:
                            count += 1
        return count

    @staticmethod
    def count_stress(model):
        count, size = 0, 0
        for agent in model.schedule.agents:
            if isinstance(agent, Family):
                count += agent.context_stress
                size += 1
        return count / size

    def run_model(self, step_count=200):

        if self.verbose:
            print('Initial number of people: ', self.schedule.get_breed_count(Person))

        # Steps are not being set here, but on superclass. Changes should be made in the step function above!
        for i in range(step_count):
            self.step()

        if self.verbose:
            print('')
            print('Final number People: ', self.schedule.get_breed_count(Person))
    def __init__(self,
                 seed=None,
                 num_nodes=50,
                 preference='attractiveness',
                 mean_male=5,
                 sd_male=1,
                 mean_female=5,
                 sd_female=1,
                 corr_results=pd.DataFrame()):

        self.uid = next(self.id_gen)
        self.num_nodes = num_nodes
        self.preference = preference
        self.mean_male = mean_male
        self.sd_male = sd_male
        self.mean_female = mean_female
        self.sd_female = sd_female
        self.corr_results = corr_results
        self.step_count = 0
        self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=0)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.datacollector = DataCollector(model_reporters={
            "number_single": number_single,
            "number_female": number_female,
            "number_union": number_union,
            "mean_attractiveness": mean_attractiveness,
            "corr_results": calculate_correlations,
            "Model Params": track_params,
            "Run": track_run
        },
                                           agent_reporters={
                                               "name":
                                               lambda x: x.name,
                                               "sex":
                                               lambda x: x.S,
                                               "attractiveness":
                                               lambda x: x.A,
                                               "relationship":
                                               lambda x: x.R,
                                               "Model Params":
                                               lambda x: track_params(x.model),
                                               "Run":
                                               lambda x: track_run(x.model)
                                           })

        # Create agents
        for i, node in enumerate(self.G.nodes()):
            person = Human(
                i,
                self,
                "MALE",
                0,
                "SINGLE",
            )
            self.schedule.add(person)
            # Add the agent to the node
            self.grid.place_agent(person, node)
        # convert half of agents to "FEMALE"
        # this need number of agents to always be dividable by 2
        # as set in the user-settable slider
        female_nodes = self.random.sample(self.G.nodes(),
                                          (int(self.num_nodes / 2)))
        for a in self.grid.get_cell_list_contents(female_nodes):
            a.S = "FEMALE"
        # here assign attractiveness based on normal distributions
        for a in self.schedule.agents:
            if a.S == 'MALE':
                A2use = np.random.normal(self.mean_male, self.sd_male, 1)[0]
                while A2use < 1 or A2use > 10:
                    A2use = np.random.normal(self.mean_male, self.sd_male,
                                             1)[0]
                a.A = A2use
            else:
                A2use = np.random.normal(self.mean_female, self.sd_female,
                                         1)[0]
                while A2use < 1 or A2use > 10:
                    A2use = np.random.normal(self.mean_female, self.sd_female,
                                             1)[0]
                a.A = A2use

        self.running = True
        self.datacollector.collect(self)
Example #50
0
class CDAmodel(Model):
    """Continuous Double Auction model with some number of agents."""
    def __init__(self,
                 supply,
                 demand,
                 s_strategy,
                 b_strategy,
                 highest_ask=100,
                 lowest_ask=0):
        self.supply = supply
        self.demand = demand
        self.num_sellers = supply.num_agents
        self.num_buyers = demand.num_agents
        self.initialize_spread()
        self.market_price = None
        self.history = Order_history()
        self.num_traded = 0
        self.num_step = 0
        # history records an order as a bid or ask only if it updates
        # the spread

        self.num_period = 1
        self.loc_period = [0]  # where each period happens

        # Sometimes trade does not happen within a period,
        # so we need variables to indicate them.
        self.no_trade = False

        # When a shift happens, I need to know it so that
        # I can calculate efficiency properly.
        self.shifted = False
        self.shifted_period = -1
        self.new_supply = None
        self.new_demand = None

        # How agents are activated at each step
        self.schedule = RandomChoiceActivation(self)
        # Create agents
        for i, cost in enumerate(self.supply.price_schedule):
            self.schedule.add(
                b_strategy(i, self, "seller", cost, supply.q_per_agent,
                           highest_ask, lowest_ask))
        for i, value in enumerate(self.demand.price_schedule):
            j = self.num_sellers + i
            self.schedule.add(
                s_strategy(j, self, "buyer", value, demand.q_per_agent,
                           highest_ask, lowest_ask))

        # Collecting data
        # self.datacollector = DataCollector(
        #     model_reporters={"Period": "num_period",
        #                      "OB": "outstanding_bid",
        #                      "OBer": get_bidder_id,
        #                      "OA": "outstanding_ask",
        #                      "OAer": get_asker_id,
        #                      "MarketPrice": "market_price",
        #                      "Traded": "traded",
        #                      "Order": lambda x: x.history.get_last_action(),
        #                      "Efficiency": compute_efficiency},
        #     agent_reporters={"Period": lambda x: x.model.num_period,
        #                      "Type": lambda x: type(x),
        #                      "Role": "role",
        #                      "Value": "value",
        #                      "Good": "good",
        #                      "Right": "right",
        #                      "Surplus": "surplus"}
        # )
        self.datacollector = DataCollector(model_reporters={
            "Step": "num_step",
            "Period": "num_period",
            "TransNum": "num_traded",
            "OB": "outstanding_bid",
            "OA": "outstanding_ask",
            "MarketPrice": "market_price",
            "Traded": "traded",
            "CumulativeActualSurplus": compute_actual_surplus,
            "TheoreticalSurplus": compute_theoretical_surplus,
            "CumulativeTS": compute_acc_theoretical_surplus,
            "Efficiency": compute_efficiency
        },
                                           agent_reporters={
                                               "Period":
                                               lambda x: x.model.num_period,
                                               "Type": lambda x: type(x),
                                               "Role": "role",
                                               "Value": "value",
                                               "Good": "good",
                                               "Right": "right",
                                               "Surplus": "surplus"
                                           })

    def initialize_spread(self):
        # Initialize outstanding bid and ask
        self.outstanding_bid = 0
        self.outstanding_bidder = None
        self.outstanding_ask = math.inf
        self.outstanding_asker = None
        self.traded = 0
        self.market_price = None

    def update_ob(self, bidder, price):
        if price > self.outstanding_bid:
            # Update the outstanding bid
            self.outstanding_bid = price
            self.outstanding_bidder = bidder

            if price > self.outstanding_ask:
                # a transaction happens
                contract_price = self.outstanding_ask
                self.execute_contract(contract_price)
                self.history.accept_bid(bidder, self.outstanding_asker,
                                        contract_price)
            else:
                self.history.submit_bid(bidder, price)
        else:
            # null order
            self.history.submit_null(bidder, None, price)

    def update_oa(self, asker, price):
        if price < self.outstanding_ask:
            # Update the outstanding ask
            self.outstanding_ask = price
            self.outstanding_asker = asker

            if price < self.outstanding_bid:
                contract_price = self.outstanding_bid
                self.execute_contract(contract_price)
                self.history.accept_ask(self.outstanding_bidder, asker,
                                        contract_price)
            else:
                # only updated the outstanding ask
                self.history.submit_ask(asker, price)
        else:
            # null order
            self.history.submit_null(None, asker, price)

    def execute_contract(self, contract_price):
        self.outstanding_bidder.buy(contract_price)
        self.outstanding_asker.sell(contract_price)
        self.market_price = contract_price
        self.traded = 1
        self.num_traded += 1

    def next_period(self, new_supply=None, new_demand=None):

        if self.num_traded == 0:
            self.no_trade = True

        if new_supply and new_demand:
            self.new_supply = new_supply
            self.new_demand = new_demand
            self.shifted = True
            self.shifted_period = self.num_period + 1

        if self.shifted:
            supply = self.new_supply
            demand = self.new_demand
        else:
            supply = self.supply
            demand = self.demand

        # Making sure the schedule is ordered as it was initialized.
        self.schedule.agents.sort(key=lambda x: x.unique_id)

        for i, cost in enumerate(supply.price_schedule):
            self.schedule.agents[i].good = supply.q_per_agent
            self.schedule.agents[i].value = cost
            self.schedule.agents[i].active = True

        for i, value in enumerate(demand.price_schedule):
            j = self.num_sellers + i
            self.schedule.agents[j].right = demand.q_per_agent
            self.schedule.agents[j].value = value
            self.schedule.agents[j].active = True

        self.num_period += 1
        self.num_traded = 0
        self.loc_period.append(self.num_step)
        self.history.next_period()

    def step(self):
        if self.traded == 1:
            self.initialize_spread()
        # print("step:", self.num_step)
        self.schedule.step()
        self.num_step += 1
        self.datacollector.collect(self)

    def plot_model(self):
        data = self.datacollector.get_model_vars_dataframe()
        data = data[data.Traded == 1]
        f = plt.figure(1)
        ax = f.add_subplot(111)
        plt.plot(data.MarketPrice)
        plt.axhline(y=self.supply.equilibrium_price,
                    color='black',
                    linestyle='dashed')
        plt.text(0.8,
                 0.9,
                 round(compute_efficiency(self), 3),
                 fontsize=20,
                 transform=ax.transAxes)
        for i in range(self.num_period):
            plt.axvline(x=self.loc_period[i],
                        color='black',
                        linestyle='dashed')
        plt.show()
class KalickHamilton(Model):
    """A model following Andre Grow's Netlogo tutorial of Kalick Hamilton 1986
    replicated using Mesa"""

    # id generator to track run number in batch run data
    id_gen = itertools.count(1)

    def __init__(self,
                 seed=None,
                 num_nodes=50,
                 preference='attractiveness',
                 mean_male=5,
                 sd_male=1,
                 mean_female=5,
                 sd_female=1,
                 corr_results=pd.DataFrame()):

        self.uid = next(self.id_gen)
        self.num_nodes = num_nodes
        self.preference = preference
        self.mean_male = mean_male
        self.sd_male = sd_male
        self.mean_female = mean_female
        self.sd_female = sd_female
        self.corr_results = corr_results
        self.step_count = 0
        self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=0)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.datacollector = DataCollector(model_reporters={
            "number_single": number_single,
            "number_female": number_female,
            "number_union": number_union,
            "mean_attractiveness": mean_attractiveness,
            "corr_results": calculate_correlations,
            "Model Params": track_params,
            "Run": track_run
        },
                                           agent_reporters={
                                               "name":
                                               lambda x: x.name,
                                               "sex":
                                               lambda x: x.S,
                                               "attractiveness":
                                               lambda x: x.A,
                                               "relationship":
                                               lambda x: x.R,
                                               "Model Params":
                                               lambda x: track_params(x.model),
                                               "Run":
                                               lambda x: track_run(x.model)
                                           })

        # Create agents
        for i, node in enumerate(self.G.nodes()):
            person = Human(
                i,
                self,
                "MALE",
                0,
                "SINGLE",
            )
            self.schedule.add(person)
            # Add the agent to the node
            self.grid.place_agent(person, node)
        # convert half of agents to "FEMALE"
        # this need number of agents to always be dividable by 2
        # as set in the user-settable slider
        female_nodes = self.random.sample(self.G.nodes(),
                                          (int(self.num_nodes / 2)))
        for a in self.grid.get_cell_list_contents(female_nodes):
            a.S = "FEMALE"
        # here assign attractiveness based on normal distributions
        for a in self.schedule.agents:
            if a.S == 'MALE':
                A2use = np.random.normal(self.mean_male, self.sd_male, 1)[0]
                while A2use < 1 or A2use > 10:
                    A2use = np.random.normal(self.mean_male, self.sd_male,
                                             1)[0]
                a.A = A2use
            else:
                A2use = np.random.normal(self.mean_female, self.sd_female,
                                         1)[0]
                while A2use < 1 or A2use > 10:
                    A2use = np.random.normal(self.mean_female, self.sd_female,
                                             1)[0]
                a.A = A2use

        self.running = True
        self.datacollector.collect(self)

    def single_union_ratio(self):
        try:
            return number_state(self, "SINGLE") / number_state(self, "UNION")
        except ZeroDivisionError:
            return math.inf

    def do_match_singles(self):
        for a in self.schedule.agents:
            if a.S == 'MALE' and a.R == 'SINGLE':
                a.date_someone()

    def do_calculate_decision_probabilities(self):
        for a in self.schedule.agents:
            if a.R == 'SINGLE':
                a.calculate_decision_probabilities()

    def do_union_decisions(self):
        for a in self.schedule.agents:
            if a.S == 'MALE' and a.R == 'SINGLE':
                a.take_union_decision()

    def step(self):
        # add to step counter
        self.step_count += 1
        self.schedule.step()
        self.do_match_singles()
        self.do_calculate_decision_probabilities()
        self.do_union_decisions()
        # collect data
        self.datacollector.collect(self)
        # if all agents in union or 51 steps past, stop.
        if number_single(self) == 0 or self.step_count == 51:
            self.running = False

    def run_model(self, n):
        for i in range(n):
            self.step()
Example #52
0
File: model.py Project: o-date/abm
class VirusOnNetwork(Model):
    """A virus model with some number of agents"""
    def __init__(self,
                 num_nodes=10,
                 avg_node_degree=3,
                 initial_outbreak_size=1,
                 virus_spread_chance=0.4,
                 virus_check_frequency=0.4,
                 recovery_chance=0.3,
                 gain_resistance_chance=0.5):

        self.num_nodes = num_nodes
        prob = avg_node_degree / self.num_nodes
        self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=prob)
        self.grid = NetworkGrid(self.G)
        self.schedule = RandomActivation(self)
        self.initial_outbreak_size = initial_outbreak_size if initial_outbreak_size <= num_nodes else num_nodes
        self.virus_spread_chance = virus_spread_chance
        self.virus_check_frequency = virus_check_frequency
        self.recovery_chance = recovery_chance
        self.gain_resistance_chance = gain_resistance_chance

        self.datacollector = DataCollector({
            "Infected": number_infected,
            "Susceptible": number_susceptible,
            "Resistant": number_resistant
        })

        # Create agents
        for i, node in enumerate(self.G.nodes()):
            a = VirusAgent(i, self, State.SUSCEPTIBLE,
                           self.virus_spread_chance,
                           self.virus_check_frequency, self.recovery_chance,
                           self.gain_resistance_chance)
            self.schedule.add(a)
            # Add the agent to the node
            self.grid.place_agent(a, node)

        # Infect some nodes
        infected_nodes = random.sample(self.G.nodes(),
                                       self.initial_outbreak_size)
        for a in self.grid.get_cell_list_contents(infected_nodes):
            a.state = State.INFECTED

        self.running = True
        self.datacollector.collect(self)

    def resistant_susceptible_ratio(self):
        try:
            return number_state(self, State.RESISTANT) / number_state(
                self, State.SUSCEPTIBLE)
        except ZeroDivisionError:
            return math.inf

    def step(self):
        self.schedule.step()
        # collect data
        self.datacollector.collect(self)

    def run_model(self, n):
        for i in range(n):
            self.step()
Example #53
0
    def __init__(self, height=40, width=40,
                 initial_families=1000,
                 metro='BRASILIA',
                 gender_stress=.8,
                 under_influence=.1,
                 has_gun=.1,
                 is_working_pct=.8,
                 chance_changing_working_status=.05,
                 pct_change_wage=.05,
                 model_scale=1000,
                 quarantine=False,
                 dissuasion=True,
                 data_year=2010):
        """
        A violence violence model of Brazilian metropolis

        """
        super().__init__()
        # Set parameters
        self.height = height
        self.width = width

        self.initial_families = initial_families
        self.metro = metro

        self.gender_stress = gender_stress
        self.under_influence = under_influence
        self.has_gun = has_gun
        self.is_working_pct = is_working_pct
        self.chance_changing_working_status = chance_changing_working_status
        self.pct_change_wage = pct_change_wage
        self.model_scale = model_scale
        self.quarantine = quarantine
        self.dissuasion = dissuasion
        self.data_year = data_year
        self.neighborhood_stress = dict()

        self.schedule = RandomActivationByBreed(self)
        self.grid = MultiGrid(self.height, self.width, torus=True)
        # Model reporters. How they work: lambda function passes model and other parameters.
        # Then another function may iterate over each 'agent in model.schedule.agents'
        # Then server is going to collect info using the keys in model_reporters dictionary
        model_reporters = {
            "Denounce": lambda m: self.count_type_citizens(m, 'denounce'),
            "Got attacked": lambda m: self.count_type_citizens(m, 'got_attacked'),
            "Females": lambda m: self.count_type_citizens(m, 'female'),
            "Stress": lambda m: self.count_stress(m)}
        self.datacollector = DataCollector(model_reporters=model_reporters)

        # Create people ---------------------------------------------------
        # Parameters to choose metropolitan region
        # More details available at input/population
        params = dict()
        params['PROCESSING_ACPS'] = [self.metro]
        params['MEMBERS_PER_FAMILY'] = 2.5
        params['INITIAL_FAMILIES'] = self.initial_families
        params['DATA_YEAR'] = self.data_year
        people, families = generator.main(params=params)
        # General random data for each individual
        n = sum([len(f) for f in families])
        working = np.random.choice([True, False], n, p=[self.is_working_pct, 1 - self.is_working_pct])
        influence = np.random.choice([True, False], n, p=[self.under_influence, 1 - self.under_influence])
        gun = np.random.choice([True, False], n, p=[self.has_gun, 1 - self.has_gun])
        i = 0
        for fam in families:
            # 1. Create a family.
            x = self.random.randrange(self.width)
            y = self.random.randrange(self.height)
            # Create a family
            family = Family(self.next_id(), self, (x, y))
            # Add family to grid
            self.grid.place_agent(family, (x, y))
            self.schedule.add(family)
            # Marriage procedures
            engaged = ['male_adult', 'female_adult']
            to_marry = list()
            # Add people to families
            for each in fam:
                person = people.loc[each]
                doe = Person(self.next_id(), self, (x, y),
                             # From IBGE's sampling
                             gender=person.gender,
                             age=person.age,
                             color=person.cor,
                             address=person.AREAP,
                             years_study=person.years_study,
                             reserve_wage=person.wage,
                             # End of sampling
                             is_working=working[i],
                             under_influence=influence[i],
                             has_gun=gun[i])
                # Marrying
                if len(engaged) > 0:
                    if person.category in engaged:
                        engaged.remove(person.category)
                        to_marry.append(doe)
                # Change position in the random list previously sampled
                i += 1
                self.grid.place_agent(doe, (x, y))
                self.schedule.add(doe)
                family.add_agent(doe)
            # 2. Marry the couple
            if len(to_marry) == 2:
                to_marry[0].assign_spouse(to_marry[1])

            # 3. Update number of family members
            for member in family.members.values():
                member.num_members_family = len(family.members)

        self.running = True
        self.datacollector.collect(self)
Example #54
0
    def __init__(self, monitored_statistic, show_schools, show_restaurants):
        """
        Create a new InfectedModel
        """
        self.schedule = BaseScheduler(self)
        self.grid = GeoSpace()
        self.steps = 0
        self.counts = None
        self.reset_counts()
        self.monitored_statistic = 'infected-per-home-series'
        self.show_schools = show_schools
        self.show_restaurants = show_restaurants
        self.maximum = {self.monitored_statistic: 0}
        self.minimum = {self.monitored_statistic: sys.maxsize}

        with open(LOG_FILE) as json_file:
            self.simulation_data = json.load(json_file)

        #for key in self.simulation_data[self.monitored_statistic]:
        #    for v in self.simulation_data[self.monitored_statistic][key]:
        #        if v > self.maximum[self.monitored_statistic]: self.maximum[self.monitored_statistic] = v
        #        if v < self.minimum[self.monitored_statistic]: self.minimum[self.monitored_statistic] = v
        self.minimum['infected-per-home-series'] = 0
        self.maximum['infected-per-home-series'] = 500

        self.running = True
        self.datacollector = DataCollector({
            "infected": get_infected_count,
            "susceptible": get_susceptible_count,
            "recovered": get_recovered_count,
            "dead": get_dead_count,
        })

        # Neighboorhoods
        AC = AgentCreator(NeighbourhoodAgent, {"model": self})
        neighbourhood_agents = AC.from_file(geojson_neighborhoods,
                                            unique_id=self.unique_id)
        for agent in neighbourhood_agents:
            for neighborhood in NEIGHBORHOODS['features']:
                if agent.unique_id == neighborhood['properties']['NAME']:
                    agent2feature[agent.unique_id] = neighborhood
                    break
        self.grid.add_agents(neighbourhood_agents)

        # Schools
        AC = AgentCreator(SchoolAgent, {"model": self})
        school_agents = AC.from_file(geojson_schools, unique_id=self.unique_id)
        for agent in school_agents:
            for school in SCHOOLS['features']:
                if agent.unique_id == school['properties']['NAME']:
                    agent2feature[agent.unique_id] = school
                    break
        self.grid.add_agents(school_agents)

        # Restaurants
        AC = AgentCreator(RestaurantAgent, {"model": self})
        restaurant_agents = AC.from_file(geojson_restaurants,
                                         unique_id=self.unique_id)
        for agent in restaurant_agents:
            for restaurant in RESTAURANTS['features']:
                if agent.unique_id == restaurant['properties']['NAME']:
                    agent2feature[agent.unique_id] = restaurant
                    break
        self.grid.add_agents(restaurant_agents)

        for agent in neighbourhood_agents + school_agents:
            self.schedule.add(agent)

        self.datacollector.collect(self)
class ClimateMigrationModel(Model):
    def __init__(   self, num_counties, preferences, network_type, \
                    climate_threshold, limited_radius=True, init_time=0):
        super().__init__()
        global TICK
        TICK = init_time
        self.num_agents = 0
        self.agent_index = 0
        self.preferences = preferences
        self.limited_radius = limited_radius
        self.upper_network_size = 3
        self.network_type = network_type
        self.climate_threshold = climate_threshold
        self.schedule = SimultaneousActivation(self)
        self.G = create_graph()
        self.num_counties = num_counties
        self.nodes = self.G.nodes()
        self.grid = NetworkGrid(self.G)
        self.county_climate_ranking = []
        self.county_population_list = [0] * self.num_counties
        self.county_flux = [0] * self.num_counties
        self.deaths = []
        self.births = []
        self.county_income = {}
        self.datacollector = DataCollector(model_reporters={"County Population": lambda m1: list(m1.county_population_list),
                                                            "County Influx": lambda m2: list(m2.county_flux),
                                                            "Deaths": lambda m3: m3.deaths,
                                                            "Births": lambda m4: m4.births,
                                                            "Total Population": lambda m5: m5.num_agents})

    def add_agents(self):
        """
        Adds agents based on 2013 ACS population data.
        """
        cumulative_population_list = get_cumulative_population_list()
        self.county_population_list = get_population_list()

        county = 0   # keeps track of which county each agent should be placed in
        index = 0   # keeps track of each agent's unique_id

        # keep creating agents until county population is reached
        while index < cumulative_population_list[county]:
            # create agent
            agent = Household(index, self)
            # place agent in appropriate county
            self.grid.place_agent(agent, list(self.nodes)[county])
            # add agent to schedule
            self.schedule.add(agent)
            # set agent's original_pos attribute
            agent.original_pos = agent.pos
            # initialize all other agent attributes
            agent.initialize_agent()
            # if running model with heterogeneous preferences, set agent preference
            if self.preferences:
                agent.initialize_preference()

            # update index
            index += 1

            # if done with county and not at last county, increase county
            if index == cumulative_population_list[county] and county < self.num_counties - 1:
                county += 1

        # after all agents are added, set model attributes
        self.num_agents = cumulative_population_list[self.num_counties-1]
        self.agent_index = cumulative_population_list[self.num_counties-1]

    def initialize_all_random_networks(self):
        """
        Initializes random networks for all agents in model.
        """
        for a in self.schedule.agents:
            a.initialize_random_network()

    def initialize_all_income_networks(self):
        """
        Initializes income-based networks for all agents in model.
        """
        for a in self.schedule.agents:
            a.initialize_income_network()

    def initialize_all_age_networks(self):
        """
        Initializes age-based networks for all agents in model.
        """
        for a in self.schedule.agents:
            a.initialize_age_network()

    def initialize_all_income_age_networks(self):
        """
        Initializes income and age-based networks for all agents in model.
        """
        for a in self.schedule.agents:
            a.initialize_income_age_network()

    def initialize_all_families(self):
        """
        Initializes families for all agents in model.
        """
        for a in self.schedule.agents:
            a.initialize_family()

    def update_population(self):
        """
        Updates population by adding and removing agents.
        """
        # keep track of number of deaths and births per county
        self.deaths = [0]*self.num_counties
        self.births = [0]*self.num_counties

        # remove agents (death)
        # loop through all agents
        for agent in self.schedule.agents:
            # source: https://www.ssa.gov/oact/STATS/table4c6.html#ss
            # calculate death probability by age in the united states
            if random.random() < 0.0001*(math.e**(0.075*agent.age)):
                # keep track of deaths by county
                self.deaths[agent.pos] += 1
                # remove agent from model
                self.grid._remove_agent(agent, agent.pos)
                # remove agent from schedule
                self.schedule.remove(agent)
                # update number of agents
                self.num_agents -= 1

        # add agents (birth)
        # loop through all counties
        for county in range(self.num_counties):
            # source: https://www.cdc.gov/nchs/fastats/births.htm
            # access current population
            current_population = self.county_population_list[county]
            # calculate how many agents should be added
            to_add = current_population//100 # birth rate
            # update number of agents
            self.num_agents += to_add

            # add specified number of agents
            for count in range(to_add):
                # update agent index
                self.agent_index += 1
                # create new agent
                agent = Household(self.agent_index, self)
                # place agent in current county
                self.grid.place_agent(agent, county)
                # add agent to schedule
                self.schedule.add(agent)

                # initialize agent attributes and networks
                
                # agents are assumed to be 18 as that is the lower bound of a householder's age
                agent.age = 18
                # based on age, income is assigned
                agent.initialize_income(random.random())
                # based on income, tenure is assigned
                agent.initialize_tenure(random.random())
                # input-specified network is initialized
                agent.initialize_network()
                # family is initialized
                agent.initialize_family()
                if self.preferences:
                    agent.initialize_preference()
                # original position is set
                agent.original_pos = agent.pos
                # keep track of births by county
                self.births[agent.pos] += 1

        # loop through counties, update population counts
        for county in self.nodes:
            self.county_population_list[county] = len(self.G.node[county]['agent'])

    def update_climate(self):
        """
        Update climate variables based on NOAA's predictions.

        Index 1 represents number of days above 90 degrees Fahrenheit.
        Index 4 represents number of days with < 1 inch of rain.
        Index 7 represents number of days without rain.
        Indexes 3, 6, and 9 are the yearly increases/decreases for these estimates.
        The update function is a simple linear function.
        
        Note: More accurate climate data could be integrated by importing
        more climate explorer data.
        """
        for n in self.nodes:
            self.G.node[n]['climate'][1] += self.G.node[n]['climate'][3]
            self.G.node[n]['climate'][4] += self.G.node[n]['climate'][6]
            self.G.node[n]['climate'][7] += self.G.node[n]['climate'][9]

    def rank_by_climate(self):
        """
        Create an ordered list of counties, from least hot/dry climate to
        most hot/dry climate.
        """
        # initialize lists to store data
        heat_data = []
        dry_data = []
        heat_dry_data = []

        # loop through counties in order
        for county in self.nodes:
            # access and store all heat/dry data
            heat_data.append(self.G.node[county]['climate'][1])
            dry_data.append(self.G.node[county]['climate'][7])

        # find max heat/dry data
        max_heat = max(heat_data)
        max_dry = max(dry_data)

        # normalize data based on max value
        heat_data = [(e/max_heat) for e in heat_data]
        dry_data = [(e/max_dry) for e in dry_data]

        # add normalized data
        for county in range(self.num_counties):
            heat_dry_data.append(heat_data[county] + dry_data[county])

        # convert to numpy array
        heat_dry_data = np.array(heat_dry_data)
        # returns indices that would sort an array (in this case,
        # returns county id's from best to worst climate)
        county_climate_rank = np.argsort(heat_dry_data)
        # convert to list, update model attribute
        self.county_climate_ranking = list(county_climate_rank)

    def update_income_counts(self):
        """
        Update income distribution by county.
        """
        # loop through counties in order
        for county in range(self.num_counties):
            # initialize list
            self.county_income[county] = [0]*10
        # loop through agents
        for agent in self.schedule.agents:
            # update dictionary based on agent data
            self.county_income[agent.pos][agent.income-1] += 1
        # income counts are printed at the beginning and end of run
        print(self.county_income)

    def get_preference_distribution(self):
        """
        TODO: docstring
        """
        preference_list = [0]*5
        for agent in self.schedule.agents:
            preference_list[agent.preference] += 1
        print(preference_list)


    def step(self):
        """
        Advance the model by one step.
        """
        global TICK
        # update climate ranking
        self.rank_by_climate()
        # advance all agents by one step
        self.schedule.step()
        # update population
        self.update_population()
        # update climate
        self.update_climate()
        # collect data
        self.datacollector.collect(self)
        # update step counter
        TICK += 1
Example #56
0
class InfectedModel(Model):
    """Model class for a simplistic infection model."""

    # Geographical parameters for desired map
    MAP_COORDS = COORDS[CITY]
    unique_id = "NAME"

    def __init__(self, monitored_statistic, show_schools, show_restaurants):
        """
        Create a new InfectedModel
        """
        self.schedule = BaseScheduler(self)
        self.grid = GeoSpace()
        self.steps = 0
        self.counts = None
        self.reset_counts()
        self.monitored_statistic = 'infected-per-home-series'
        self.show_schools = show_schools
        self.show_restaurants = show_restaurants
        self.maximum = {self.monitored_statistic: 0}
        self.minimum = {self.monitored_statistic: sys.maxsize}

        with open(LOG_FILE) as json_file:
            self.simulation_data = json.load(json_file)

        #for key in self.simulation_data[self.monitored_statistic]:
        #    for v in self.simulation_data[self.monitored_statistic][key]:
        #        if v > self.maximum[self.monitored_statistic]: self.maximum[self.monitored_statistic] = v
        #        if v < self.minimum[self.monitored_statistic]: self.minimum[self.monitored_statistic] = v
        self.minimum['infected-per-home-series'] = 0
        self.maximum['infected-per-home-series'] = 500

        self.running = True
        self.datacollector = DataCollector({
            "infected": get_infected_count,
            "susceptible": get_susceptible_count,
            "recovered": get_recovered_count,
            "dead": get_dead_count,
        })

        # Neighboorhoods
        AC = AgentCreator(NeighbourhoodAgent, {"model": self})
        neighbourhood_agents = AC.from_file(geojson_neighborhoods,
                                            unique_id=self.unique_id)
        for agent in neighbourhood_agents:
            for neighborhood in NEIGHBORHOODS['features']:
                if agent.unique_id == neighborhood['properties']['NAME']:
                    agent2feature[agent.unique_id] = neighborhood
                    break
        self.grid.add_agents(neighbourhood_agents)

        # Schools
        AC = AgentCreator(SchoolAgent, {"model": self})
        school_agents = AC.from_file(geojson_schools, unique_id=self.unique_id)
        for agent in school_agents:
            for school in SCHOOLS['features']:
                if agent.unique_id == school['properties']['NAME']:
                    agent2feature[agent.unique_id] = school
                    break
        self.grid.add_agents(school_agents)

        # Restaurants
        AC = AgentCreator(RestaurantAgent, {"model": self})
        restaurant_agents = AC.from_file(geojson_restaurants,
                                         unique_id=self.unique_id)
        for agent in restaurant_agents:
            for restaurant in RESTAURANTS['features']:
                if agent.unique_id == restaurant['properties']['NAME']:
                    agent2feature[agent.unique_id] = restaurant
                    break
        self.grid.add_agents(restaurant_agents)

        for agent in neighbourhood_agents + school_agents:
            self.schedule.add(agent)

        self.datacollector.collect(self)

    def reset_counts(self):
        self.counts = {
            "susceptible": 0,
            "infected": 0,
            "recovered": 0,
            "dead": 0,
            "safe": 0,
            "hotspot": 0,
        }

    def step(self):
        #if self.steps >= len(self.simulation_data['infected-series']) - 2:
        if self.steps > 50:
            self.running = False
            return
        self.steps += 1
        self.reset_counts()
        self.schedule.step()
        self.grid._recreate_rtree(
        )  # Recalculate spatial tree, because agents are moving
        self.datacollector.collect(self)
        return True
Example #57
0
    def __init__(
        self,
        height=40,
        width=40,
        citizen_density=0.7,
        cop_density=0.074,
        citizen_vision=7,
        cop_vision=7,
        legitimacy=0.8,
        max_jail_term=1000,
        active_threshold=0.1,
        arrest_prob_constant=2.3,
        movement=True,
        initial_unemployment_rate=0.1,
        corruption_level=0.1,
        susceptible_level=0.3,
        honest_level=0.6,
        max_iters=1000,
    ):

        super().__init__()
        self.height = height
        self.width = width
        self.citizen_density = citizen_density
        self.cop_density = cop_density
        self.citizen_vision = citizen_vision
        self.cop_vision = cop_vision
        self.legitimacy = legitimacy
        self.max_jail_term = max_jail_term
        self.active_threshold = active_threshold
        self.arrest_prob_constant = arrest_prob_constant
        self.movement = movement
        self.initial_unemployment_rate = initial_unemployment_rate
        self.corruption_level = corruption_level
        self.susceptible_level = susceptible_level
        self.max_iters = max_iters
        self.iteration = 0
        self.schedule = RandomActivation(self)
        self.grid = Grid(height, width, torus=True)
        model_reporters = {
            "Quiescent":
            lambda m: self.count_type_citizens(m, "Quiescent"),
            "Active":
            lambda m: self.count_type_citizens(m, "Active"),
            "Jailed":
            lambda m: self.count_jailed(m),
            "Employed":
            lambda m: self.count_employed(m),
            "Corrupted":
            lambda m: self.count_moral_type_citizens(m, "Corrupted"),
            "Honest":
            lambda m: self.count_moral_type_citizens(m, "Honest"),
            "Susceptible":
            lambda m: self.count_moral_type_citizens(m, "Susceptible")
        }
        agent_reporters = {
            "x": lambda a: a.pos[0],
            "y": lambda a: a.pos[1],
            "breed": lambda a: a.breed,
            "jail_sentence": lambda a: getattr(a, "jail_sentence", None),
            "condition": lambda a: getattr(a, "condition", None),
            "arrest_probability":
            lambda a: getattr(a, "arrest_probability", None),
            "is_employed": lambda a: getattr(a, "is_employed", None),
            "moral_condition": lambda a: getattr(a, "moral_condition", None),
        }
        self.datacollector = DataCollector(model_reporters=model_reporters,
                                           agent_reporters=agent_reporters)
        unique_id = 0
        if self.cop_density + self.citizen_density > 1:
            raise ValueError(
                "Cop density + citizen density must be less than 1")

        if self.initial_unemployment_rate > 1:
            raise ValueError(
                "initial_unemployment_rate must be between [0,1] ")

        if self.corruption_level + self.susceptible_level > 1:
            raise ValueError("moral level must be less than 1 ")

        for (contents, x, y) in self.grid.coord_iter():
            if self.random.random() < self.cop_density:
                cop = Cop(unique_id, self, (x, y), vision=self.cop_vision)
                unique_id += 1
                self.grid[y][x] = cop
                self.schedule.add(cop)
            elif self.random.random() < (self.cop_density +
                                         self.citizen_density):
                moral_state = "Honest"
                is_employed = 1
                if self.random.random() < self.initial_unemployment_rate:
                    is_employed = 0
                p = self.random.random()
                if p < self.corruption_level:
                    moral_state = "Corrupted"
                elif p < self.corruption_level + self.susceptible_level:
                    moral_state = "Susceptible"

                citizen = Citizen(
                    unique_id,
                    self,
                    (x, y),
                    #updated hardship formula: if agent is employed hardship is alleviated
                    hardship=self.random.random() -
                    (is_employed * self.random.uniform(0.05, 0.15)),
                    legitimacy=self.legitimacy,
                    #updated regime legitimacy, so inital corruption rate is taken into consideration
                    regime_legitimacy=self.legitimacy - self.corruption_level,
                    risk_aversion=self.random.random(),
                    active_threshold=self.active_threshold,
                    #updated threshold: if agent is employed threshold for rebelling is raised
                    threshold=self.active_threshold +
                    (is_employed * self.random.uniform(0.05, 0.15)),
                    vision=self.citizen_vision,
                    is_employed=is_employed,
                    moral_state=moral_state,
                )
                unique_id += 1
                self.grid[y][x] = citizen
                self.schedule.add(citizen)

        self.running = True
        self.datacollector.collect(self)
    def __init__(self, height, width, density, wms, wts, wus, td, ve, ae):

        # Initialize model parameters
        self.height = height
        self.width = width
        self.density = density
        self.weeklyCampaignSpend = wms
        self.weeklyTrainingSpend = wts
        self.weeklyUsabilitySpend = wus

        #initialize HITL related parameters
        self.trainingDataWeeklyInput = td
        self.vizEffect = ve

        self.learningRate = 0
        self.dataInstances = 10000
        self.algoAccuracy = ae

        self.algoEffect = self.algoAccuracy *0.1


        # Set up model objects

        #this sets the activation order of the agents (when they make their moves) to be random each step
        self.schedule = RandomActivation(self)

        #this creates the physical grid we are using to simulate word of mouth spread of the model
        self.grid = Grid(height, width, torus=False)

        #these use the Mesa DataCollector method to create several trackers to collect data from the model run
        self.dc_output = DataCollector(model_reporters={"Avg Output Value Per Person Per Week": compute_avg_output})
        self.dc_tracker = DataCollector(model_reporters={"Average IA": compute_avg_ia})
        self.dc_adoption = DataCollector({"Potential Trialer": lambda m: self.count_type(m, "Potential Trialer"),
                                "Trialer": lambda m: self.count_type(m, "Trialer"),
                                "Adopter": lambda m: self.count_type(m, "Adopter"), "Defector": lambda m: self.count_type(m, "Defector"), "Evangelist": lambda m: self.count_type(m, "Evangelist")})
        self.dc_trialers =DataCollector({"Trialer": lambda m: self.count_type(m, "Trialer")})
        self.dc_algo = DataCollector({"Learning Rate": compute_learning_rate})

        self.dc_master=DataCollector({"Potential Trialer": lambda m: self.count_type(m, "Potential Trialer"),
                                "Trialer": lambda m: self.count_type(m, "Trialer"),
                                "Adopter": lambda m: self.count_type(m, "Adopter"),
                                "Defector": lambda m: self.count_type(m, "Defector"),
                                "Evangelist": lambda m: self.count_type(m, "Evangelist"),
                                "Avg Output Value Per Person": compute_avg_output,
                                "Total Differential in Population": hitl_adv_differential,
                                "Algo Accuracy": compute_algo_accuracy,
                                "Algo Accuracy Increase": compute_learning_rate,
                                "Total Dataset Size": compute_data_instances,
                                "Algorithm Effect": compute_algo_effect,
                                "Avg Data Collection Ouput": compute_avg_dc,
                                "Avg Data Interpretation/Analysis Output": compute_avg_di,
                                "Avg Interpreting Actions Output": compute_avg_ia,
                                "Avg Coaching Output": compute_avg_coaching,
                                "Avg Review Output": compute_avg_review})

        #the logic for the creation of the agents, as well as setting the initial values of the agent parameters
        for x in range(self.width):
                for y in range(self.height):
                    if random.random() < self.density:
                        new_consultant = Consultant(self, (x, y), np.random.normal(60, 10), np.random.normal(70, 10), 0)
                        if y == 0:
                            new_consultant.condition = "Trialer"
                        self.grid[y][x] = new_consultant
                        self.schedule.add(new_consultant)

        #run the model when the class is called
        self.running = True
Example #59
0
    def __init__(self,
                 height=115,
                 width=85,
                 config_file='inputs/dieba_init.csv',
                 econ_file='inputs/econ_init.csv',
                 tree_file='inputs/tree.csv',
                 draftprice=250000,
                 livestockprice=125000,
                 defaultrot=['C', 'M', 'G'],
                 tract=0,
                 tractfile='inputs/tractor_costs.csv',
                 rentcap=0,
                 rentprice=0,
                 rentin=0,
                 rentout=0,
                 rentpct=0,
                 laborcost=30000):
        '''
        Create a new model with the given parameters.

        Args:
        height, width: dimensions of area
        config_file: path to initial owner config csv (must have 1 header row)
        econ_file: path to economics/harvest data

        '''

        # Set parameters
        self.height = height
        self.width = width
        self.draftprice = draftprice
        self.livestockprice = livestockprice
        self.defaultrot = defaultrot
        self.tract = tract
        self.tractcost = pd.read_csv(tractfile, index_col='type')
        self.rentin = rentin
        self.rentout = rentout
        self.rentcap = self.rentout  #available to rent, updates within step
        self.rentpct = rentpct
        self.laborcost = laborcost
        self.config = np.genfromtxt(config_file,
                                    dtype=int,
                                    delimiter=',',
                                    skip_header=1)
        self.nowners = self.config.shape[0]
        self.econ = pd.read_csv(econ_file, index_col=['crop', 'mgt'])
        self.tree = pd.read_csv(tree_file, index_col=['crop', 'mgt', 'age'])
        self.schedule = ActivationByBreed(self)
        self.grid = MultiGrid(self.height, self.width, torus=False)
        self.Landcollector = breedDataCollector(breed=Land,
                                                agent_reporters={
                                                    "cultivated":
                                                    lambda a: a.steps_cult,
                                                    "fallow":
                                                    lambda a: a.steps_fallow,
                                                    "potential":
                                                    lambda a: a.potential,
                                                    "suitability":
                                                    lambda a: a.suitability
                                                })
        self.CropPlotcollector = breedDataCollector(
            breed=CropPlot,
            agent_reporters={
                "owner": lambda a: a.owner,
                "plID": lambda a: a.plID,
                "crop": lambda a: a.crop,
                "mgt": lambda a: a.mgt,
                "harvest": lambda a: a.harvest,
                "GM": lambda a: a.GM,
                "pot": lambda a: a.get_land(a.pos).potential,
                "steps_cult": lambda a: a.get_land(a.pos).steps_cult,
                "suitability": lambda a: a.get_land(a.pos).suitability,
                "steps_fallow": lambda a: a.get_land(a.pos).steps_fallow
            })
        self.TreePlotcollector = breedDataCollector(breed=TreePlot,
                                                    agent_reporters={
                                                        "owner":
                                                        lambda a: a.owner,
                                                        "plID":
                                                        lambda a: a.plID,
                                                        "crop":
                                                        lambda a: a.crop,
                                                        "age": lambda a: a.age,
                                                        "harvest":
                                                        lambda a: a.harvest,
                                                        "GM": lambda a: a.GM
                                                    })
        self.Ownercollector = breedDataCollector(breed=Owner,
                                                 agent_reporters={
                                                     "owner":
                                                     lambda a: a.owner,
                                                     "hhsize":
                                                     lambda a: a.hhsize,
                                                     "cplots":
                                                     lambda a: len(a.cplots),
                                                     "trees":
                                                     lambda a: len(a.trees),
                                                     "wealth":
                                                     lambda a: a.wealth,
                                                     "expenses":
                                                     lambda a: a.expenses,
                                                     "income":
                                                     lambda a: a.income,
                                                     "draft":
                                                     lambda a: a.draft,
                                                     "livestock":
                                                     lambda a: a.livestock,
                                                     "tract":
                                                     lambda a: a.tract,
                                                     "rentout":
                                                     lambda a: a.rentout,
                                                     "rentin":
                                                     lambda a: a.rentin,
                                                     "full":
                                                     lambda a: a.full
                                                 })
        self.Modelcollector = DataCollector(model_reporters={
            "rentout": lambda m: m.rentout,
            "rentin": lambda m: m.rentin
        })

        # Create land
        land_suitability = np.genfromtxt("inputs/db_suitability.csv",
                                         delimiter=',')
        land_feasibility = np.genfromtxt("inputs/db_feasibility_nop.csv",
                                         delimiter=',')
        for _, x, y in self.grid.coord_iter():
            suitability = land_suitability[x, y]
            feasibility = land_feasibility[x, y]
            fallow = random.randrange(10)
            land = Land((x, y),
                        self,
                        suitability,
                        feasibility,
                        steps_fallow=fallow)
            self.grid.place_agent(land, (x, y))
            self.schedule.add(land)

        #Create Owner agents:
        for i in range(self.nowners):
            x = random.randrange(20, self.height - 20)
            y = random.randrange(20, self.width - 20)
            owner = i
            nplots = self.config[i, 1]
            wealth = self.config[i, 2]
            hhsize = self.config[i, 3]
            draft = self.config[i, 4]
            livestock = self.config[i, 5]
            expenses = self.config[i, 6]
            trees = self.config[i, 7]
            tract = self.config[i, 8]
            owneragent = Owner((x, y), self, owner, wealth, hhsize, draft,
                               livestock, expenses, trees, tract)
            self.grid.place_agent(owneragent, (x, y))
            self.schedule.add(owneragent)
            for j in range(nplots):
                #Create CropPlots for each owner:
                # place near owner pos then move
                plotowner = owneragent.owner
                plID = j
                crop = self.defaultrot[random.randint(
                    0, (len(self.defaultrot) - 1))]
                # cpx = x+random.randrange(-1*owneragent.vision,owneragent.vision)
                # cpy = y+random.randrange(-1*owneragent.vision,owneragent.vision)
                croppl = CropPlot(owneragent.pos, self, plotowner, plID, crop)
                owneragent.cplots.append(croppl)
                self.grid.place_agent(croppl, (x, y))
                croppl.move()  #move to best pos'n near owner
                while croppl.get_land(croppl.pos).potential == 0:
                    croppl.move()
                croppl.get_land(croppl.pos).steps_cult = random.randrange(10)
                self.schedule.add(croppl)
            for k in range(trees):
                plotowner = owneragent.owner
                plID = k
                treepl = TreePlot(owneragent.pos, self, plotowner, plID)
                owneragent.trees.append(treepl)
                self.grid.place_agent(treepl, (x, y))
                treepl.move()
                self.schedule.add(treepl)
        self.running = True
Example #60
0
class BankReservesModel(Model):

    # grid height
    grid_h = 20
    # grid width
    grid_w = 20
    """init parameters "init_people", "rich_threshold", and "reserve_percent"
       are all UserSettableParameters"""
    def __init__(
        self,
        height=grid_h,
        width=grid_w,
        init_people=2,
        rich_threshold=10,
        reserve_percent=50,
    ):
        self.height = height
        self.width = width
        self.init_people = init_people
        self.schedule = RandomActivation(self)
        self.grid = MultiGrid(self.width, self.height, torus=True)
        # rich_threshold is the amount of savings a person needs to be considered "rich"
        self.rich_threshold = rich_threshold
        self.reserve_percent = reserve_percent
        # see datacollector functions above
        self.datacollector = DataCollector(
            model_reporters={
                "Rich": get_num_rich_agents,
                "Poor": get_num_poor_agents,
                "Middle Class": get_num_mid_agents,
                "Savings": get_total_savings,
                "Wallets": get_total_wallets,
                "Money": get_total_money,
                "Loans": get_total_loans
            },
            agent_reporters={"Wealth": lambda x: x.wealth})

        # create a single bank for the model
        self.bank = Bank(1, self, self.reserve_percent)

        # create people for the model according to number of people set by user
        for i in range(self.init_people):
            # set x coordinate as a random number within the width of the grid
            x = random.randrange(self.width)
            # set y coordinate as a random number within the height of the grid
            y = random.randrange(self.height)
            p = Person(i, (x, y), self, True, self.bank, self.rich_threshold)
            # place the Person object on the grid at coordinates (x, y)
            self.grid.place_agent(p, (x, y))
            # add the Person object to the model schedule
            self.schedule.add(p)

        self.running = True

    def step(self):
        # collect data
        self.datacollector.collect(self)
        # tell all the agents in the model to run their step function
        self.schedule.step()

    def run_model(self):
        for i in range(self.run_time):
            self.step()