class FoodSupplyModel(Model): def __init__(self, fridgesCount, width, height): self.fridgesCount = fridgesCount self.running = True self.grid = MultiGrid(height, width, torus=False) self.schedule = DayScheduler(self) self.productTypes = ["A", "B", "C"] self.fridges = [] self.isSupplyInProgress = False self.orders = [] def randomFreeCoordinates(): while True: x = random.randrange(self.grid.width) y = random.randrange(self.grid.height) if self.grid.is_cell_empty((x, y)): return (x, y) def balancedInitialContents(capacity): amount = capacity / len(self.productTypes) return {product: amount for product in self.productTypes} for i in range(self.fridgesCount): capacity = 30 dailyUsages = [{"A": 3, "B": 2, "C": 1}, {"A": 4, "B": 1, "C": 2}, {"A": 2, "B": 2, "C": 3}] fridge = FridgeAgent(i, capacity, dailyUsages[i % 3], balancedInitialContents(capacity)) self.fridges.append(fridge) self.grid.place_agent(fridge, randomFreeCoordinates()) self.supplier = SupplierAgent(1000) self.truck = TruckAgent(0, capacity=100) self.schedule.add(self.truck) # self.grid.place_agent(self.truck, randomFreeCoordinates()) self.grid.place_agent(self.truck, (0,0)) def nextDay(self): for fridge in self.fridges: fridge.step(self) self.supplier.step(self) self.orders = [] self.isSupplyInProgress = True def step(self): self.schedule.step() def run_model(self, n): for i in range(n): self.step()
class CommuteModel(Model): """This agent-based model seeks to demonstrate the effect of spatial inequality on the way agents commute.""" def __init__(self, N, initial_wealth, cost_per_pixel, pt_cost, cost_to_move, pt_aval, width, height, city_pos): self.num_agents = N self.grid = MultiGrid(width, height, True) self.schedule = RandomActivation(self) # place commute agents for unique_id in range(self.num_agents): x = random.randrange(self.grid.width) y = random.randrange(self.grid.height) pos = (x, y) if self.grid.is_cell_empty(pos): a = CommuteAgent(unique_id, self, pos, city_pos, initial_wealth, cost_per_pixel, pt_cost, cost_to_move, pt_aval) self.schedule.add(a) self.grid.place_agent(a, pos) self.grid.place_agent(CityAgent(city_pos), city_pos) self.ginicollector = DataCollector( model_reporters={"Gini": compute_gini}, agent_reporters={"Wealth": "wealth"}) self.avgcollector = DataCollector( model_reporters={"Average Income": compute_avg_wealth}, agent_reporters={"Wealth": "wealth"}) self.ginicollector.collect(self) self.avgcollector.collect(self) self.running = True def step(self): self.schedule.step() # collect data self.ginicollector.collect(self) self.avgcollector.collect(self) def run_model(self, n): for i in range(n): self.step()
class Themepark(Model): def __init__(self, N_attr, N_cust, width, height, strategy, theme, max_time, weight, adaptive): self.max_time = max_time self.N_attr = N_attr self.penalty_per = PENALTY_PERCENTAGE self.weight = weight self.adaptive = adaptive self.strategies = STRATEGIES self.x_list, self.y_list, self.positions = xlist, ylist, positions self.x_list, self.y_list, self.positions = get_attraction_coordinates( WIDTH, HEIGHT, self.N_attr, theme) self.happinesses = [] self.path_coordinates = get_coordinates(WIDTH, HEIGHT, NUM_OBSTACLES, self.N_attr, theme) self.N_cust = N_cust # num of customer agents self.total_steps = 0 self.cust_ids = N_cust self.strategy = strategy self.grid = MultiGrid(width, height, torus=False) self.schedule = BaseScheduler(self) self.schedule_Attraction = BaseScheduler(self) self.schedule_Customer = BaseScheduler(self) self.totalTOTAL = 0 #TODO: DEZE NAAM VERANDEREN self.attractions = self.make_attractions() self.attraction_history = self.make_attr_hist() self.park_score = [] self.data_dict = {} self.hist_random_strat = [] self.hist_close_strat = [] self.all_rides_list = [] self.strategy_composition = self.make_strategy_composition() self.customers = self.add_customers(self.N_cust) self.monitor = Monitor(self.max_time, self.N_attr, self.positions) self.running = True # TODO: ALS HET GOED IS KUNNEN AL DEZE INITS WEG, MAAR DIT MOETEN WE WEL NOG EVEN DUBBEL CHECKEN # --> dit is gecheckt op het runnen van main_cluster_random_noise # self.theme = theme # self.starting_positions = [[int((WIDTH/2)-1), 0], [int(WIDTH/2), 0], [int((WIDTH/2)+1), 0]] # self.width = width # self.height = height # self.data = [] # self.data_customers = [] # self.memory = 5 # self.customer_score = [] # self.only_random = False # self.total_waited_time = 0 # Initialize dictionary of attractions for attraction in self.get_attractions(): self.data_dict[attraction.unique_id] = ({ "id": attraction.unique_id, "length": attraction.attraction_duration, "waiting_list": [] }) # TODO ADD COMMENT (SNAP NIET WAT DE DATACOLLECTOR IS) if len(self.strategies) == 6: self.datacollector = DataCollector({ "Random": lambda m: self.strategy_counter(self.strategies[0]), "0.00": lambda m: self.strategy_counter(self.strategies[1]), "0.25": lambda m: self.strategy_counter(self.strategies[2]), "0.50": lambda m: self.strategy_counter(self.strategies[3]), "0.75": lambda m: self.strategy_counter(self.strategies[4]), "1.00": lambda m: self.strategy_counter(self.strategies[5]), }) else: self.datacollector = DataCollector({ "0.00": lambda m: self.strategy_counter(self.strategies[0]), "0.25": lambda m: self.strategy_counter(self.strategies[1]), "0.50": lambda m: self.strategy_counter(self.strategies[2]), "0.75": lambda m: self.strategy_counter(self.strategies[3]), "1.00": lambda m: self.strategy_counter(self.strategies[4]), }) self.datacollector2 = DataCollector( {"score": lambda m: self.make_score()}) def make_score(self): """ Get the efficiency score """ ideal = {} cust_in_row = 0 for i in range(len(self.get_attractions())): ideal[i] = self.N_cust / self.N_attr cust_in_row += self.get_attractions()[i].N_current_cust tot_difference = 0 for i in range(len(self.get_attractions())): difference = abs(cust_in_row / self.N_attr - self.get_attractions()[i].N_current_cust) tot_difference += difference fraction_not_right = (tot_difference / self.N_cust) return abs(1 - (fraction_not_right)) * cust_in_row / self.N_cust def make_attr_hist(self): """ Initialize a dictionary in which the history of the attractions can be added in. """ attraction_history = {} for attraction in self.get_attractions(): attraction_history[attraction] = [0] * (self.max_time + 1) return attraction_history def strategy_counter(self, strategy): """ Count how many customers of different strategies are at the attractions """ counter_total = {} for attraction_pos in self.positions: agents = self.grid.get_neighbors(attraction_pos, moore=True, radius=0, include_center=True) counter = 0 for agent in self.customers: if agent.weight == strategy: counter += 1 return counter def make_strategy_composition(self): """ TODO: ANNEMIJN KAN JIJ HIER COMMENTS BIJ DOEN? + RANDOM_TEST_4 WEGHALEN """ if self.strategy == "Random_test_4": self.strategies = ["Random_test_4", 0.0, 0.25, 0.50, 0.75, 1.0] dict = { self.strategies[0]: 1 / 6, self.strategies[1]: 0.20, self.strategies[2]: 0.20, self.strategies[3]: 0.20, self.strategies[4]: 0.20, self.strategies[5]: 0.20 } composition_list = [] for i in range(len(self.strategies)): if i == 0: dict[self.strategies[i]] = FRACTION_RANDOM continue else: composition_list.append(random.randint(0, 100)) sum_comp = sum(composition_list) sum_comp = sum_comp - sum_comp * FRACTION_RANDOM for i in range(len(self.strategies)): if i == 0: continue else: dict[self.strategies[i]] = composition_list[i - 1] / sum_comp else: dict = { self.strategies[0]: 0.20, self.strategies[1]: 0.20, self.strategies[2]: 0.20, self.strategies[3]: 0.20, self.strategies[4]: 0.20 } composition_list = [] for i in range(len(self.strategies)): composition_list.append(random.randint(0, 100)) sum_comp = sum(composition_list) sum_comp = sum_comp for i in range(len(self.strategies)): dict[self.strategies[i]] = composition_list[i - 1] / sum_comp return dict def make_attractions(self): """ Initialize attractions on fixed position. """ attractions = {} for i in range(self.N_attr): pos = (self.x_list[i], self.y_list[i]) if self.grid.is_cell_empty(pos): name = str(i) a = Attraction(i, self, pos, name, self.N_cust, self.weight) attractions[i] = a self.schedule_Attraction.add(a) self.grid.place_agent(a, pos) return attractions def get_attractions(self): """ Get a list with all attractions. """ agents = self.grid.get_neighbors(mid_point, moore=True, radius=RADIUS, include_center=True) attractions = [] for agent in agents: if type(agent) == Attraction: attractions.append(agent) return attractions def calculate_people(self): """ Calculate how many customers are in which attraction. """ counter_total = {} for attraction_pos in self.positions: agents = self.grid.get_neighbors(attraction_pos, moore=True, radius=0, include_center=True) counter = 0 for agent in agents: if type(agent) is Customer: counter += 1 else: attraction = agent attraction.N_current_cust = counter counter_total[attraction.unique_id] = counter return list(counter_total.values()) def add_customers(self, N_cust, added=False): """ Initialize customers on random positions. """ weights_list = [] if self.adaptive is True: for j in self.strategy_composition.keys(): for i in range(round(N_cust * self.strategy_composition[j])): weights_list.append(j) if len(weights_list) < self.N_cust: rand = random.choice(self.strategies) weights_list.append(rand) elif len(weights_list) > self.N_cust: rand = random.choice(weights_list) weights_list.remove(rand) else: # if the strategy is not random add weights to weights_list if self.strategy is not "Random": for i in range(round(N_cust)): weights_list.append(self.weight) cust_list = [] for i in range(N_cust): pos_temp = [ random.randint(0, WIDTH - 1), random.randint(0, HEIGHT - 1) ] rand_x, rand_y = pos_temp[0], pos_temp[1] pos = (rand_x, rand_y) if added is True: i = self.cust_ids if self.strategy == "Random_test_4": if weights_list[i] == "Random_test_4": strategy = "Random_test_4" else: strategy = "Closest_by" else: strategy = self.strategy # Set weight if weights_list == []: weight = None else: weight = weights_list[i] # Initialize customer and add customer to the model a = Customer(i, self, pos, self.x_list, self.y_list, self.positions, strategy, weight, self.adaptive) self.schedule_Customer.add(a) self.grid.place_agent(a, pos) cust_list.append(a) return cust_list def calc_waiting_time(self): """ Calculate the waitingtime per attraction """ counter_total = {} attractions = self.get_attractions() for attraction in attractions: counter_total[ attraction.unique_id] = attraction.current_waitingtime return counter_total def calculate_people_sorted(self): """ Calculate how many customers are in which attraction. Returns a SORTED LIST. For example: indexes = [3, 2, 5, 1, 4] indicates that attraction3 has the least people waiting. """ counter_total = {} for attraction_pos in self.positions: agents = self.grid.get_neighbors(attraction_pos, moore=True, radius=0, include_center=True) counter = 0 for agent in agents: if type(agent) is Customer: counter += 1 else: attraction = agent attraction.N_current_cust = counter self.attraction_history[attraction][self.totalTOTAL] = counter counter_total[attraction.unique_id] = counter return counter_total def make_route(self): """ Draw coordinates of a possible path. """ for i in range(len(self.path_coordinates)): pos = self.path_coordinates[i] if pos not in self.positions: # Create path agent path = Route(i, self, pos) self.schedule.add(path) self.grid.place_agent(path, pos) # TODO: THEMEPARK SCORE GEBRUIKEN WE NIET MEER, DIT ALLEMAAL VERWIJDEREN OVERAL? def get_themepark_score(self): """ Get score of a themepark based on: - A total of all waitingtimes for every customer - The total number of rides taken """ attractions = self.get_attractions() total_wait, total_rides = 0, 0 for attraction in attractions: total_wait += attraction.current_waitingtime if attraction.current_a is not None: total_rides += 1 if total_rides == 0: return total_rides return (total_wait / total_rides) def get_strategy_history(self): """ Update history with how many customers chose which strategy. """ customers = self.get_customers() randomstrat, closebystrat = 0, 0 for customer in customers: if customer.strategy == "Random" or customer.strategy == "Random_test_4": randomstrat += 1 elif customer.strategy == "Closest_by": closebystrat += 1 self.hist_random_strat.append(randomstrat) self.hist_close_strat.append(closebystrat) def get_customers(self): """ Returns a list of all the customers in the themepark. """ agents = self.grid.get_neighbors(mid_point, moore=True, radius=RADIUS, include_center=True) customers = [] # Add customers to list for agent in agents: if type(agent) == Customer: customers.append(agent) return customers def get_data_customers(self): """ Return dictionary with data of customers. """ data = {} agents = self.grid.get_neighbors(mid_point, moore=True, radius=RADIUS, include_center=True) for agent in agents: if type(agent) is Customer: data[agent.unique_id] = { "totalwaited": agent.total_ever_waited, "visited_attractions": agent.nmbr_attractions, "strategy": agent.strategy, "swapped_strat": agent.strategy_swap_hist } return data # TODO: NET ALS THEMEPARK SCORE GEBRUIKEN WE DIT NEIT MEER TOCH???? def calc_hapiness(self): """ Calculate mean hapiness of all customers, based on: - How many rides were taken - Number of times in the same attraction - Total waiting time """ customers = self.get_customers() scores = [] for customer in customers: history = customer.history values = list(history.values()) total_rides = sum(values) if total_rides != 0: scores.append(total_rides / self.N_attr - self.totalTOTAL / customer.total_ever_waited) else: return None scores = np.interp(scores, (min(scores), max(scores)), (1, 10)) return np.mean(scores) def get_history_list(self): """ Create a list with the history of the customers. """ customers = self.get_customers() histories = {} for customer in customers: history = customer.history values = list(history.values()) histories[customer.unique_id] = values return histories def final(self): """ End run and return data. """ # Create list with at every time step the amount of attractions that are active attractions = self.get_attractions() self.all_rides_list = [0] * len(attractions[0].in_attraction_list) for attraction in attractions: for i in range(len(attraction.in_attraction_list)): self.all_rides_list[i] += attraction.in_attraction_list[i] # Change the all_rides_list into fractions for i in range(len(self.all_rides_list)): self.all_rides_list[i] /= self.N_attr # Initialize history list and get agents hist_list = [] agents = self.grid.get_neighbors(mid_point, moore=True, radius=RADIUS, include_center=True) # Save history of all customers cust_data = self.get_data_customers() for agent in agents: if type(agent) is Customer: sum_attr = sum(agent.history.values()) if sum_attr > 0: hist_list.append(agent.strategy_swap_hist) else: hist_list.append(agent.strategy_swap_hist) histories = self.get_history_list() # Save data try: pickle.dump(self.datacollector.get_model_vars_dataframe(), open("../data/strategy_history.p", 'wb')) pickle.dump(self.datacollector2.get_model_vars_dataframe(), open("../data/eff_score_history.p", 'wb')) pickle.dump(cust_data, open("../data/customers.p", 'wb')) pickle.dump(self.park_score[-1], open("../data/park_score.p", "wb")) pickle.dump(self.happinesses, open("../data/hapiness.p", "wb")) pickle.dump(histories, open("../data/cust_history.p", 'wb')) except: pickle.dump(self.datacollector.get_model_vars_dataframe(), open("data/strategy_history.p", 'wb')) pickle.dump(self.datacollector2.get_model_vars_dataframe(), open("data/eff_score_history.p", 'wb')) pickle.dump(cust_data, open("data/customers.p", 'wb')) pickle.dump(self.park_score[-1], open("data/park_score.p", "wb")) pickle.dump(self.happinesses, open("data/hapiness.p", "wb")) pickle.dump(histories, open("data/cust_history.p", 'wb')) try: pickle.dump(self.all_rides_list, open("../data/all_rides.p", "wb")) except: pickle.dump(self.all_rides_list, open("data/all_rides.p", "wb")) print() print("RUN HAS ENDED") print() def save_data(self): """ Save data of all attractions and customers. """ # Get info waitinglines = self.calc_waiting_time() for i in range(len(self.attractions)): self.data_dict[i]["waiting_list"].append(waitinglines.get(i)) self.park_score.append(sum(waitinglines.values())) self.happinesses.append(self.calc_hapiness()) def step(self): """ Advance the model by one step. """ # Take a step if max steps is not reached if self.totalTOTAL < self.max_time: self.totalTOTAL += 1 self.schedule.step() self.datacollector.collect(self) self.datacollector2.collect(self) self.schedule_Attraction.step() self.schedule_Customer.step() self.total_steps += 1 self.save_data() self.get_strategy_history() # Stop simulation else: for key in self.attraction_history.keys(): y = self.attraction_history[key] x = list(range(0, self.max_time)) self.final()
class EV_Model(Model): def __init__(self, N=50, width=20, height=20, n_poles=10, vision=10, grid_positions="random", initial_bravery=10, battery_size=25, open_grid=True): self.battery_size = battery_size self.initial_bravery = initial_bravery self.num_agents = N self.open = open_grid if self.open == True: self.grid = MultiGrid(width, height, True) else: self.grid = MultiGrid(width, height, False) self.schedule = RandomActivationByBreed(self) self.vision = vision self.grid_size = width # adds CPs based on the input grid position if grid_positions == "circle": center_grid = (int(width / 2), int(height / 2)) circle_list = PointsInCircum(round(self.grid_size / 4), int(N * n_poles)) for i, coord in enumerate(circle_list): new_coord = (coord[0] + center_grid[0], coord[1] + center_grid[1]) charge_pole = Charge_pole(i, new_coord, self) self.grid.place_agent(charge_pole, new_coord) self.schedule.add(charge_pole) elif grid_positions == "big circle": center_grid = (int(width / 2), int(height / 2)) circle_list = PointsInCircum(round(self.grid_size / 2 - 1), int(N * n_poles)) for i, coord in enumerate(circle_list): new_coord = (coord[0] + center_grid[0], coord[1] + center_grid[1]) charge_pole = Charge_pole(i, new_coord, self) self.grid.place_agent(charge_pole, new_coord) self.schedule.add(charge_pole) elif grid_positions == "random": for i in range(int(N * n_poles)): # Add the agent to a random grid cell empty_coord = self.grid.find_empty() charge_pole = Charge_pole(i, empty_coord, self) self.grid.place_agent(charge_pole, empty_coord) self.schedule.add(charge_pole) elif grid_positions == "LHS": coord_list = np.round( lhs(2, samples=int(N * n_poles), criterion="m") * (self.grid_size - 1)) for i in range(int(N * n_poles)): coord = tuple((int(coord_list[i][0]), int(coord_list[i][1]))) if self.grid.is_cell_empty(coord): charge_pole = Charge_pole(i, coord, self) self.grid.place_agent(charge_pole, coord) else: empty_coord = self.grid.find_empty() charge_pole = Charge_pole(i, empty_coord, self) self.grid.place_agent(charge_pole, empty_coord) self.schedule.add(charge_pole) # Create EV agents for i in range(self.num_agents): # Add the agent to a random empty grid cell home_pos = self.grid.find_empty() work_pos = self.grid.find_empty() EV = EV_Agent(i, self, self.vision, home_pos, work_pos, initial_bravery, battery_size) self.schedule.add(EV) self.grid.place_agent(EV, home_pos) self.totalEVs = i self.datacollector = DataCollector( agent_reporters={}, model_reporters={ "Avg_Battery": mean_all_battery, "Usage": avg_usage, "High_Usage": high_usage, "Low_Usage": low_usage, "Total_attempts": totalAttempts, "Percentage_failed": percentageFailed, "Average_lifespan": averageLifespan, "lower25": lowest_25_percent, "timeInState": time_in_state, "unique_battery": specific_battery, "Num_agents": count_agents, "EVs": lambda m: m.schedule.get_breed_count(EV_Agent) }) self.running = True self.current_EVs = self.totalEVs def step(self): self.schedule.step() self.datacollector.collect(self) self.stableAgents() def stableAgents(self): while self.current_EVs < self.num_agents: home_pos = self.grid.find_empty() work_pos = self.grid.find_empty() EV = EV_Agent(self.totalEVs, self, self.vision, home_pos, work_pos, self.initial_bravery, self.battery_size) self.grid.place_agent(EV, home_pos) self.schedule.add(EV) self.totalEVs += 1 self.current_EVs += 1
class Battlefield(Model): """ Główna klasa modelu w której wszystko sie dzieje Arg: width (int): szerokość planszy height (int): wysokość planszy """ def __init__(self, width, height): super().__init__() self.width = width self.height = height self.survived_steps_blue = 0 self.survived_steps_red = 0 self.grid = MultiGrid(width, height, False) self.schedule = RandomActivation(self) self.running = True self.spawn_from_file() self.initial_red_count = self.count_units("#ff0000") self.initial_blue_count = self.count_units("#00aab2") self.tmp = self.count_cost() self.starting_cost_blue = self.tmp[1][0] self.starting_cost_red = self.tmp[0][0] self.datacollector = DataCollector( model_reporters={ "Suma przeżytych rund każdej jednostki do kosztu całej armii - czerwoni": compute_cost_red, "Suma przeżytych rund każdej jednostki do kosztu całej armii - niebiescy": compute_cost_blue }) self.datacollector_health = DataCollector( model_reporters={ "Punkty życia armii czerwonej": compute_health_red, "Punkty życia armii niebieskiej": compute_health_blue }) def spawn_from_file(self): units = read_from_file('Data/army.txt') """ Wkłada jednostki z listy na planszę :return: """ for element in units: if element[2] == 'I': a = Infantry(self.current_id, self) elif element[2] == 'A': a = Archers(self.current_id, self) elif element[2] == 'C': a = Cavalry(self.current_id, self) elif element[2] == 'R': a = Rock(self.current_id, self) self.next_id() a.set_color(element[3]) a.timer = random.choice([True, False]) self.schedule.add(a) if self.grid.is_cell_empty((element[0], element[1])): self.grid.place_agent(a, (element[0], element[1])) else: print("Unable to place unit on that cell") def step(self): """ Uruchamia losowo wszystkich agentów :return: """ self.schedule.step() self.is_simulation_over() self.datacollector.collect(self) self.datacollector_health.collect(self) def count_cost(self): """ Funkcja do liczenia kosztów armii :return: zwraca tablice krotek (koszt,kolor) """ costs = [] temp = [0, '#ff0000', 0, '#00aab2'] for a in self.schedule.agents: if a.color == "#ff0000": temp[0] += a.cost elif a.color == "#00aab2": temp[2] += a.cost costs.append((temp[0], temp[1])) costs.append((temp[2], temp[3])) return costs def count_units(self, color): """ Zlicza ilość jednostek danego koloru :param color: Kolor jednostek jakie ma liczyć :return: zwraca ilość jednostek """ counter = 0 for a in self.schedule.agents: if a.color == color: counter += 1 return counter def is_simulation_over(self): """ Sprawdza czy symulacja sie zakończyła :return: """ temp = self.count_cost() if temp[0][0] == 0 or temp[1][0] == 0: self.running = False to_file( self.write_results(), "Data/results" + str(self.width) + "x" + str(self.height) + ".txt") def write_results(self): string = "" if self.who_won() == 1: string += "Blue won with " string += str(self.count_units("#00aab2")) string += " units left." string += " Starting with || Blue units " string += str(self.initial_blue_count) string += " - " string += str(self.initial_red_count) string += " Red units\n" else: string += "Red won with " string += str(self.count_units("#ff0000")) string += " units left" string += " Starting with || Blue units " string += str(self.initial_blue_count) string += " - " string += str(self.initial_red_count) string += " Red units\n" return string def who_won(self): """ Sprawdza kto wygrał :return: zwraca 1 kiedy wygrali niebiescy i 0 jak wygralki czerwoni """ temp = self.count_cost() if temp[0][0] > 0: return 0 else: return 1
class SquashBee(Model): def __init__(self, height=50, width=50, time=0, density_bee=50, density_gender_bee=50, gain_polline_raccolto=40, density_zucca=50, prob_accoppiamento=50, offsetX=5, offsetY=5): self.height = height self.width = width self.time = 200 self.density_bee = density_bee self.density_gender_bee = density_gender_bee self.gain_polline_raccolto = gain_polline_raccolto self.density_zucca = density_zucca self.prob_accoppiamento = prob_accoppiamento self.offsetX = offsetX self.offsetY = offsetY self.anno = 1 self.schedule = RandomActivation(self) self.grid = MultiGrid(self.width, self.height, torus=True) self.datacollector = DataCollector({ "Zucche_fiori": lambda m: self.count_type(m, "Flower"), "Zucche": lambda m: self.count_type(m, "Zucca"), "Seed": lambda m: self.count_type(m, "Seed"), "Api": lambda m: self.count_type(m, "Bee"), "Larve": lambda m: self.count_type(m, "Bee_son") }) # metto le api nella griglia for i in range(self.density_bee): x = self.random.randrange(2, 33) y = self.random.randrange(2, 33) new_bee = Bee((x, y), self, self.density_gender_bee, self.gain_polline_raccolto, 120) self.grid.place_agent(new_bee, (x, y)) self.schedule.add(new_bee) # metto i fiori delle zucche nella griglia for i in range(self.density_zucca): x = self.random.randrange(5, 30) y = self.random.randrange(5, 30) new_zucca = Zucca_flower((x, y), self, self.prob_accoppiamento, 45) self.grid._place_agent((x, y), new_zucca) self.schedule.add(new_zucca) # metto i fiori nella griglia for i in range(150): x = self.random.randrange(self.height) y = self.random.randrange(self.width) new_f = flower((x, y), self) self.grid._place_agent((x, y), new_f) self.schedule.add(new_f) self.running = True self.datacollector.collect(self) def step(self): self.time += 1 #fioritura primaverile if self.time == 90: # metto i fiori nella griglia for i in range(150): x = self.random.randrange(self.height) y = self.random.randrange(self.width) if (self.grid.is_cell_empty((x, y))): new_f = flower((x, y), self) self.grid._place_agent((x, y), new_f) self.schedule.add(new_f) # semina ogni anno if self.time == 160: # metto i semi delle zucche nella griglia if self.anno % 2 == 0: for i in range(self.density_zucca): x = self.random.randrange(5 + self.offsetX, 30 + self.offsetX) y = self.random.randrange(5 + self.offsetY, 30 + self.offsetY) if (self.grid.is_cell_empty((x, y))): new_seme = Zucca_seed((x, y), self) self.grid._place_agent((x, y), new_seme) self.schedule.add(new_seme) if self.anno % 2 == 1: for i in range(self.density_zucca): x = self.random.randrange(5, 30) y = self.random.randrange(5, 30) if (self.grid.is_cell_empty((x, y))): new_seme = Zucca_seed((x, y), self) self.grid._place_agent((x, y), new_seme) self.schedule.add(new_seme) # reset anno if self.time == 360: self.time = 0 self.anno += 1 self.schedule.step() # collect data self.datacollector.collect(self) @staticmethod def count_type(model, agent_type): """ Helper method to count trees in a given condition in a given model. """ count = 0 for agent in model.schedule.agents: if agent.type_agent == agent_type: count += 1 return count
class SleepAnimals_sinDataColl(Model): ''' Analysis of the evolution of sleep in animals ''' # Default values width = 40 height = 40 number_food_patch = 40 number_sleep_patch = 40 interdistance_factor = 0.7 intradistance_factor = 0.2 fp_depletion_tick = 60 def __init__(self, model_id , genome,width = 40, height = 40, number_food_patch = 40, number_sleep_patch = 40, interdistance_factor = 0.7, intradistance_factor = 0.2, fp_depletion = 60, sleep_and_food_gainfactor = 1): super().__init__() # Setting Parameters self.model_id = model_id self.width = width self.height = height self.number_food_patch = number_food_patch self.number_sleep_patch = number_sleep_patch self.interdistance_factor = interdistance_factor self.intradistance_factor = intradistance_factor self.sue_factor = sleep_and_food_gainfactor self.genome = genome self.fp_center_x = 0 self.fp_center_y = 0 self.sp_center_x = 0 self.sp_center_y = 0 self.current_id_food_patch = 0 self.current_id_sleep_patch = 0 self.fp_tick_to_depletion = fp_depletion self.schedule = RandomActivation(self) self.grid = MultiGrid(self.width, self.height, torus = False) #self.datacollector = DataCollector( # agent_reporters={"Food_fitness" : lambda a: a.fitness_food, # "Sleep_fitness" : lambda a: a.fitness_sleep, # "Fitness" : lambda a: a.fitness, # "Mode" : lambda a: a.mode, # "Direction" : lambda a: a.lookingto}) # Picking Centers for Food and Sleep Patches self.interdistance = 0 self.intradistance = 0 self.findingcenters() # Populating Food Patches self.available_food_patches = self.grid.get_neighborhood( (self.fp_center_x, self.fp_center_y), False, True, self.intradistance ) i = 0 while i < self.number_food_patch: self.new_foodpatch() i += 1 # Populating Sleep Patches self.available_sleep_patches = self.grid.get_neighborhood( (self.sp_center_x, self.sp_center_y), False, True, self.intradistance ) i = 0 while i < self.number_sleep_patch: current_spot = random.choice(self.available_sleep_patches) if not self.grid.is_cell_empty(current_spot): continue sleep_patch = SleepPatch( self.next_id_sleeppatch(), self, current_spot ) self.grid.place_agent( sleep_patch, current_spot ) i += 1 # Adding Animal to the world current_spot = random.choice( self.grid.empties ) animal = Animal( self.next_id(), self, current_spot, self.genome, self.sue_factor, self.sue_factor ) self.grid.place_agent( animal, current_spot ) self.schedule.add( animal ) def step(self): '''Advance the model by one step.''' # self.datacollector.collect(self) self.schedule.step() def findingcenters(self): max_manhattan_length = self.height + self.width self.interdistance = int(max_manhattan_length * self.interdistance_factor) self.intradistance = int(max_manhattan_length * self.intradistance_factor) fp_center_x = 0 fp_center_y = 0 sp_center_x = 0 sp_center_y = 0 centers_selected = False while not centers_selected: fp_center_x = random.randrange(self.width) fp_center_y = random.randrange(self.height) fp_center = (fp_center_x, fp_center_y) available_spots_food = self.grid.get_neighborhood(fp_center, False, False, self.intradistance) if len(available_spots_food) < 80: continue if self.interdistance > 0: list_centers_sp = list( set( self.grid.get_neighborhood(fp_center, False, False, self.interdistance + 1) ) - set( self.grid.get_neighborhood(fp_center, False, False, self.interdistance - 1) ) ) if len(list_centers_sp) < 5: continue else: list_centers_sp = [(fp_center_x,fp_center_y)] sp_center = random.choice(list_centers_sp) (sp_center_x, sp_center_y) = sp_center available_spots_sleep = self.grid.get_neighborhood(sp_center, False, False, self.intradistance) if len(available_spots_sleep) < 80: continue centers_selected = True self.fp_center_x = fp_center_x self.fp_center_y = fp_center_y self.sp_center_x = sp_center_x self.sp_center_y = sp_center_y def next_id_foodpatch(self): """ Return the next unique ID for food patches, increment current_id""" self.current_id_food_patch += 1 a = 'M' + str(self.model_id) + 'F' + str(self.current_id_food_patch) return a def next_id_sleeppatch(self): """ Return the next unique ID for sleep patches, increment current_id""" self.current_id_sleep_patch += 1 a = 'M' + str(self.model_id) + 'S' + str(self.current_id_sleep_patch) return a def new_foodpatch(self): spot_found = False while not spot_found : current_spot = random.choice(self.available_food_patches) if not self.grid.is_cell_empty(current_spot): continue food_patch = FoodPatch(self.next_id_foodpatch(), self, current_spot, self.fp_tick_to_depletion) self.grid.place_agent(food_patch, current_spot) spot_found = True def arrayRGB_clusters(self): available_spots = np.full( (self.grid.width , self.grid.height , 3) , 255) for coordinates in self.available_sleep_patches: (x, y) = coordinates available_spots[x][y]= [100, 0, 150] for coordinates in self.available_food_patches: (x, y) = coordinates available_spots[x][y]= [10, 150, 0] return available_spots def arrayRGB_display(self): RGBdisplay = np.full((self.grid.width, self.grid.height,3), 255) for cell in self.grid.coord_iter(): cell_content, x, y = cell a = list(cell_content) if len(a) == 0: RGBdisplay[x][y] = [255,255,255] elif len(a) == 1: if isinstance(a[0], SleepPatch): RGBdisplay[x][y] = [100,0,150] elif isinstance(a[0], FoodPatch): RGBdisplay[x][y] = [10,150,0] elif isinstance(a[0], Animal): RGBdisplay[x][y] = [0,0,0] else: pass elif len(a) == 2: RGBdisplay[x][y] = [0,0,0] else: pass return RGBdisplay def array2D_display(self): display2D = np.zeros((self.grid.width, self.grid.height)) for cell in self.grid.coord_iter(): cell_content, x, y = cell a = list(cell_content) if len(a) == 0: display2D[x][y] = 0 elif len(a) == 1: if isinstance(a[0], SleepPatch): display2D[x][y] = 10 elif isinstance(a[0], FoodPatch): display2D[x][y] = 20 elif isinstance(a[0], Animal): display2D[x][y] = 30 else: pass else: pass return display2D
class Themepark(Model): def __init__(self, N_attr, N_cust, width, height, strategy, theme, max_time, weight, adaptive): self.theme = theme self.max_time = max_time self.N_attr = N_attr self.penalty_per = PENALTY_PERCENTAGE self.weight = weight self.adaptive = adaptive self.strategies = STRATEGIES self.x_list, self.y_list, self.positions = xlist, ylist, positions self.x_list, self.y_list, self.positions = get_attraction_coordinates(WIDTH, HEIGHT, self.N_attr, theme) self.happinesses = [] self.starting_positions = [[int((WIDTH/2)-1), 0], [int(WIDTH/2), 0], [int((WIDTH/2)+1), 0]] self.path_coordinates = get_coordinates(WIDTH, HEIGHT, NUM_OBSTACLES, self.N_attr, theme) self.N_attr = N_attr # num of attraction agents self.N_cust = N_cust # num of customer agents self.width = width self.height = height self.total_steps = 0 self.cust_ids = N_cust self.strategy = strategy self.grid = MultiGrid(width, height, torus=False) self.schedule = BaseScheduler(self) self.schedule_Attraction = BaseScheduler(self) self.schedule_Customer = BaseScheduler(self) self.totalTOTAL = 0 self.attractions = self.make_attractions() self.attraction_history = self.make_attr_hist() self.running = True self.data = [] self.data_customers = [] self.park_score = [] self.data_dict = {} self.hist_random_strat = [] self.hist_close_strat = [] self.all_rides_list = [] self.strategy_composition = self.make_strategy_composition() self.memory = 5 self.customer_score = [] self.customers = self.add_customers(self.N_cust) self.only_random = False for attraction in self.get_attractions(): self.data_dict[attraction.unique_id] = ({ "id": attraction.unique_id, "length": attraction.attraction_duration, "waiting_list": []}) if len(self.strategies) == 6: self.datacollector = DataCollector( {"Random": lambda m: self.strategy_counter(self.strategies[0]), "0.00": lambda m: self.strategy_counter(self.strategies[1]), "0.25": lambda m: self.strategy_counter(self.strategies[2]), "0.50": lambda m: self.strategy_counter(self.strategies[3]), "0.75": lambda m: self.strategy_counter(self.strategies[4]), "1.00": lambda m: self.strategy_counter(self.strategies[5]), }) else: self.datacollector = DataCollector( {"0.00": lambda m: self.strategy_counter(self.strategies[0]), "0.25": lambda m: self.strategy_counter(self.strategies[1]), "0.50": lambda m: self.strategy_counter(self.strategies[2]), "0.75": lambda m: self.strategy_counter(self.strategies[3]), "1.00": lambda m: self.strategy_counter(self.strategies[4]), }) self.datacollector2 = DataCollector( {"score": lambda m: self.make_score()}) self.total_waited_time = 0 self.monitor = Monitor(self.max_time, self.N_attr, self.positions) def make_score(self): ideal = {} cust_in_row = 0 for i in range(len(self.get_attractions())): ideal[i] = self.N_cust/self.N_attr cust_in_row += self.get_attractions()[i].N_current_cust tot_difference = 0 for i in range(len(self.get_attractions())): difference = abs(cust_in_row/self.N_attr - self.get_attractions()[i].N_current_cust) tot_difference += difference fraction_not_right = (tot_difference/self.N_cust) return abs(1-(fraction_not_right)) * cust_in_row/self.N_cust def make_attr_hist(self): attraction_history = {} for attraction in self.get_attractions(): attraction_history[attraction] = [0] * (self.max_time + 1) return attraction_history def strategy_counter(self, strategy): counter_total = {} for attraction_pos in self.positions: agents = self.grid.get_neighbors( attraction_pos, moore=True, radius=0, include_center=True ) counter = 0 for agent in self.customers: if agent.weight == strategy: counter += 1 return counter def make_strategy_composition(self): if self.strategy == "Random_test_4": self.strategies = ["Random_test_4", 0.0, 0.25, 0.50, 0.75, 1.0] dict = {self.strategies[0]: 1/6, self.strategies[1]:0.20, self.strategies[2]:0.20, self.strategies[3]:0.20, self.strategies[4]:0.20, self.strategies[5]: 0.20} composition_list = [] for i in range(len(self.strategies)): if i == 0: dict[self.strategies[i]] = FRACTION_RANDOM continue else: composition_list.append(random.randint(0,100)) sum_comp = sum(composition_list) sum_comp = sum_comp - sum_comp * FRACTION_RANDOM for i in range(len(self.strategies)): if i == 0: continue else: dict[self.strategies[i]] = composition_list[i-1] /sum_comp else: dict = {self.strategies[0]: 0.20, self.strategies[1]:0.20, self.strategies[2]:0.20, self.strategies[3]:0.20, self.strategies[4]:0.20} composition_list = [] for i in range(len(self.strategies)): composition_list.append(random.randint(0,100)) sum_comp = sum(composition_list) sum_comp = sum_comp for i in range(len(self.strategies)): dict[self.strategies[i]] = composition_list[i-1] /sum_comp return dict def make_attractions(self): """ Initialize attractions on fixed position.""" attractions = {} for i in range(self.N_attr): pos = (self.x_list[i], self.y_list[i]) if self.grid.is_cell_empty(pos): name = str(i) a = Attraction(i, self, pos, name, self.N_cust, self.weight) attractions[i] = a self.schedule_Attraction.add(a) self.grid.place_agent(a, pos) return attractions def get_attractions(self): """ Get a list with all attractions """ agents = self.grid.get_neighbors( mid_point, moore=True, radius=RADIUS, include_center=True) attractions = [] for agent in agents: if type(agent) == Attraction: attractions.append(agent) return attractions def add_customers(self, N_cust, added=False): """ Initialize customers on random positions.""" weights_list = [] if self.adaptive is True: for j in self.strategy_composition.keys(): for i in range(round(N_cust*self.strategy_composition[j])): weights_list.append(j) if len(weights_list) < self.N_cust: rand = random.choice(self.strategies) weights_list.append(rand) elif len(weights_list) > self.N_cust: rand = random.choice(weights_list) weights_list.remove(rand) else: if self.strategy is not "Random": # do what normally is done for i in range(round(N_cust)): weights_list.append(self.weight) cust_list = [] # weight_counter = 0 # pick_weight = 0 for i in range(N_cust): # pos_temp = random.choice(self.starting_positions) pos_temp = [random.randint(0,WIDTH-1), random.randint(0,HEIGHT-1)] rand_x, rand_y = pos_temp[0], pos_temp[1] pos = (rand_x, rand_y) if added is True: i = self.cust_ids if self.strategy == "Random_test_4": if weights_list[i] == "Random_test_4": strategy = "Random_test_4" else: strategy = "Closest_by" else: strategy = self.strategy # Deze if is omdat bij alleen random self.weight none is! if weights_list == []: weight = None else: weight = weights_list[i] a = Customer(i, self, pos, self.x_list, self.y_list, self.positions, strategy, weight, self.adaptive) self.schedule_Customer.add(a) self.grid.place_agent(a, pos) cust_list.append(a) return cust_list def calculate_people(self): """Calculate how many customers are in which attraction.""" counter_total = {} for attraction_pos in self.positions: agents = self.grid.get_neighbors( attraction_pos, moore=True, radius=0, include_center=True ) counter = 0 for agent in agents: if type(agent) is Customer: counter += 1 else: attraction = agent attraction.N_current_cust = counter counter_total[attraction.unique_id] = counter return list(counter_total.values()) def calc_waiting_time(self): counter_total = {} attractions = self.get_attractions() for attraction in attractions: counter_total[attraction.unique_id] = attraction.current_waitingtime return counter_total def calculate_people_sorted(self): """ Calculate how many customers are in which attraction. Returns a SORTED LIST. For example: indexes = [3, 2, 5, 1, 4] indicates that attraction3 has the least people waiting. """ counter_total = {} for attraction_pos in self.positions: agents = self.grid.get_neighbors( attraction_pos, moore=True, radius=0, include_center=True ) counter = 0 for agent in agents: if type(agent) is Customer: counter += 1 else: attraction = agent attraction.N_current_cust = counter self.attraction_history[attraction][self.totalTOTAL] = counter counter_total[attraction.unique_id] = counter return counter_total def make_route(self): """Draw coordinates of a possible path.""" for i in range(len(self.path_coordinates)): pos = self.path_coordinates[i] if pos not in self.positions: # Create path agent path = Route(i, self, pos) self.schedule.add(path) self.grid.place_agent(path, pos) def get_themepark_score(self): """ Get score of a themepark based on: - A total of all waitingtimes for every customer - TODO """ attractions = self.get_attractions() total_wait, total_rides = 0, 0 for attraction in attractions: total_wait += attraction.current_waitingtime if attraction.current_a is not None: total_rides += 1 if total_rides == 0: return total_rides return (total_wait / total_rides) def get_strategy_history(self): """ Update history with how many customers chose which strategy """ customers = self.get_customers() randomstrat, closebystrat = 0, 0 for customer in customers: if customer.strategy == "Random" or customer.strategy == "Random_test_4": randomstrat += 1 elif customer.strategy == "Closest_by": closebystrat += 1 self.hist_random_strat.append(randomstrat) self.hist_close_strat.append(closebystrat) def get_customers(self): agents = self.grid.get_neighbors( mid_point, moore=True, radius=RADIUS, include_center=True) customers = [] # Count customer agents for agent in agents: if type(agent) == Customer: customers.append(agent) return customers def get_data_customers(self): """ Return dictionary with data of customers """ data = {} agents = self.grid.get_neighbors( mid_point, moore=True, radius=RADIUS, include_center=True) for agent in agents: if type(agent) is Customer: data[agent.unique_id] = { "totalwaited": agent.total_ever_waited, "visited_attractions": agent.nmbr_attractions, "strategy": agent.strategy, "swapped_strat": agent.strategy_swap_hist } return data def calc_hapiness(self): """ Calculate mean hapiness of all customers, based on: - How many rides were taken - Number of times in the same attraction - Total waiting time """ customers = self.get_customers() scores = [] for customer in customers: history = customer.history values = list(history.values()) total_rides = sum(values) if total_rides != 0: scores.append(total_rides / self.N_attr - self.totalTOTAL / customer.total_ever_waited) else: return None scores = np.interp(scores, (min(scores), max(scores)), (1, 10)) return np.mean(scores) def get_history_list(self): customers = self.get_customers() histories = {} for customer in customers: history = customer.history values = list(history.values()) histories[customer.unique_id] = values return histories def final(self): """ Return data """ hist_list = [] agents = self.grid.get_neighbors( mid_point, moore=True, radius=RADIUS, include_center=True) attractions = self.get_attractions() self.all_rides_list = [0] * len(attractions[0].in_attraction_list) for attraction in attractions: for i in range(len(attraction.in_attraction_list)): self.all_rides_list[i] += attraction.in_attraction_list[i] for i in range(len(self.all_rides_list)): self.all_rides_list[i] /= self.N_attr print("ALL RIDES LIST", self.all_rides_list) cust_data = self.get_data_customers() for agent in agents: if type(agent) is Customer: sum_attr = sum(agent.history.values()) if sum_attr > 0: hist_list.append(agent.strategy_swap_hist) else: hist_list.append(agent.strategy_swap_hist) # print("swap:",agent.strategy_swap_hist , "sum:",sum_attr) # plt.hist(hist_list) # plt.show() histories = self.get_history_list() # save data try: pickle.dump(self.datacollector.get_model_vars_dataframe(), open("../data/strategy_history.p", 'wb')) pickle.dump(self.datacollector2.get_model_vars_dataframe(), open("../data/eff_score_history.p", 'wb')) pickle.dump(cust_data, open("../data/customers.p", 'wb')) pickle.dump(self.park_score[-1], open("../data/park_score.p", "wb")) pickle.dump(self.happinesses, open("../data/hapiness.p", "wb")) pickle.dump(histories, open("../data/cust_history.p", 'wb')) except: pickle.dump(self.datacollector.get_model_vars_dataframe(), open("data/strategy_history.p", 'wb')) pickle.dump(self.datacollector2.get_model_vars_dataframe(), open("data/eff_score_history.p", 'wb')) pickle.dump(cust_data, open("data/customers.p", 'wb')) pickle.dump(self.park_score[-1], open("data/park_score.p", "wb")) pickle.dump(self.happinesses, open("data/hapiness.p", "wb")) pickle.dump(histories, open("data/cust_history.p", 'wb')) try: pickle.dump(self.all_rides_list, open("../data/all_rides.p", "wb")) except: pickle.dump(self.all_rides_list, open("data/all_rides.p", "wb")) print() print("RUN HAS ENDED") print() def save_data(self): """Save data of all attractions and customers.""" # Get info waitinglines = self.calc_waiting_time() for i in range(len(self.attractions)): self.data_dict[i]["waiting_list"].append(waitinglines.get(i)) self.park_score.append(sum(waitinglines.values())) self.happinesses.append(self.calc_hapiness()) def step(self): """Advance the model by one step.""" if self.totalTOTAL < self.max_time: self.totalTOTAL += 1 self.schedule.step() self.datacollector.collect(self) self.datacollector2.collect(self) self.schedule_Attraction.step() self.schedule_Customer.step() # update memory of attractions # attractions = self.get_attractions() # for attraction in attractions: # attraction.update_memory() self.total_steps += 1 self.save_data() self.get_strategy_history() else: for key in self.attraction_history.keys(): y = self.attraction_history[key] x = list(range(0, self.max_time)) self.final()
class FireEvacuation(Model): MIN_HEALTH = 0.75 MAX_HEALTH = 1 MIN_SPEED = 1 MAX_SPEED = 2 MIN_NERVOUSNESS = 1 MAX_NERVOUSNESS = 10 MIN_EXPERIENCE = 1 MAX_EXPERIENCE = 10 MIN_VISION = 1 # MAX_VISION is simply the size of the grid def __init__(self, floor_plan_file, human_count, collaboration_percentage, fire_probability, visualise_vision, random_spawn, save_plots): # Load floorplan # floorplan = np.genfromtxt(path.join("fire_evacuation/floorplans/", floor_plan_file)) with open(os.path.join("fire_evacuation/floorplans/", floor_plan_file), "rt") as f: floorplan = np.matrix([line.strip().split() for line in f.readlines()]) # Rotate the floorplan so it's interpreted as seen in the text file floorplan = np.rot90(floorplan, 3) # Check what dimension our floorplan is width, height = np.shape(floorplan) # Init params self.width = width self.height = height self.human_count = human_count self.collaboration_percentage = collaboration_percentage self.visualise_vision = visualise_vision self.fire_probability = fire_probability self.fire_started = False # Turns to true when a fire has started self.save_plots = save_plots # Set up model objects self.schedule = RandomActivation(self) self.grid = MultiGrid(height, width, torus=False) # Used to start a fire at a random furniture location self.furniture_list = [] # Used to easily see if a location is a FireExit or Door, since this needs to be done a lot self.fire_exit_list = [] self.door_list = [] # If random spawn is false, spawn_list will contain the list of possible spawn points according to the floorplan self.random_spawn = random_spawn self.spawn_list = [] # Load floorplan objects for (x, y), value in np.ndenumerate(floorplan): value = str(value) floor_object = None if value is "W": floor_object = Wall((x, y), self) elif value is "E": floor_object = FireExit((x, y), self) self.fire_exit_list.append((x, y)) self.door_list.append((x, y)) # Add fire exits to doors as well, since, well, they are elif value is "F": floor_object = Furniture((x, y), self) self.furniture_list.append((x, y)) elif value is "D": floor_object = Door((x, y), self) self.door_list.append((x, y)) elif value is "S": self.spawn_list.append((x, y)) if floor_object: self.grid.place_agent(floor_object, (x, y)) self.schedule.add(floor_object) # Create a graph of traversable routes, used by agents for pathing self.graph = nx.Graph() for agents, x, y in self.grid.coord_iter(): pos = (x, y) # If the location is empty, or a door if not agents or any(isinstance(agent, Door) for agent in agents): neighbors = self.grid.get_neighborhood(pos, moore=True, include_center=True, radius=1) for neighbor in neighbors: # If there is contents at this location and they are not Doors or FireExits, skip them if not self.grid.is_cell_empty(neighbor) and neighbor not in self.door_list: continue self.graph.add_edge(pos, neighbor) # Collects statistics from our model run self.datacollector = DataCollector( { "Alive": lambda m: self.count_human_status(m, Human.Status.ALIVE), "Dead": lambda m: self.count_human_status(m, Human.Status.DEAD), "Escaped": lambda m: self.count_human_status(m, Human.Status.ESCAPED), "Incapacitated": lambda m: self.count_human_mobility(m, Human.Mobility.INCAPACITATED), "Normal": lambda m: self.count_human_mobility(m, Human.Mobility.NORMAL), "Panic": lambda m: self.count_human_mobility(m, Human.Mobility.PANIC), "Verbal Collaboration": lambda m: self.count_human_collaboration(m, Human.Action.VERBAL_SUPPORT), "Physical Collaboration": lambda m: self.count_human_collaboration(m, Human.Action.PHYSICAL_SUPPORT), "Morale Collaboration": lambda m: self.count_human_collaboration(m, Human.Action.MORALE_SUPPORT) } ) # Calculate how many agents will be collaborators number_collaborators = int(round(self.human_count * (self.collaboration_percentage / 100))) # Start placing human agents for i in range(0, self.human_count): if self.random_spawn: # Place human agents randomly pos = self.grid.find_empty() else: # Place human agents at specified spawn locations pos = random.choice(self.spawn_list) if pos: # Create a random human health = random.randint(self.MIN_HEALTH * 100, self.MAX_HEALTH * 100) / 100 speed = random.randint(self.MIN_SPEED, self.MAX_SPEED) if number_collaborators > 0: collaborates = True number_collaborators -= 1 else: collaborates = False # Vision statistics obtained from http://www.who.int/blindness/GLOBALDATAFINALforweb.pdf vision_distribution = [0.0058, 0.0365, 0.0424, 0.9153] vision = int(np.random.choice(np.arange(self.MIN_VISION, self.width + 1, (self.width / len(vision_distribution))), p=vision_distribution)) nervousness_distribution = [0.025, 0.025, 0.1, 0.1, 0.1, 0.3, 0.2, 0.1, 0.025, 0.025] # Distribution with slight higher weighting for above median nerovusness nervousness = int(np.random.choice(range(self.MIN_NERVOUSNESS, self.MAX_NERVOUSNESS + 1), p=nervousness_distribution)) # Random choice starting at 1 and up to and including 10 experience = random.randint(self.MIN_EXPERIENCE, self.MAX_EXPERIENCE) belief_distribution = [0.9, 0.1] # [Believes, Doesn't Believe] believes_alarm = np.random.choice([True, False], p=belief_distribution) human = Human(pos, health=health, speed=speed, vision=vision, collaborates=collaborates, nervousness=nervousness, experience=experience, believes_alarm=believes_alarm, model=self) self.grid.place_agent(human, pos) self.schedule.add(human) else: print("No tile empty for human placement!") self.running = True # Plots line charts of various statistics from a run def save_figures(self): DIR = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) OUTPUT_DIR = DIR + "/output" results = self.datacollector.get_model_vars_dataframe() dpi = 100 fig, axes = plt.subplots(figsize=(1920 / dpi, 1080 / dpi), dpi=dpi, nrows=1, ncols=3) status_results = results.loc[:, ['Alive', 'Dead', 'Escaped']] status_plot = status_results.plot(ax=axes[0]) status_plot.set_title("Human Status") status_plot.set_xlabel("Simulation Step") status_plot.set_ylabel("Count") mobility_results = results.loc[:, ['Incapacitated', 'Normal', 'Panic']] mobility_plot = mobility_results.plot(ax=axes[1]) mobility_plot.set_title("Human Mobility") mobility_plot.set_xlabel("Simulation Step") mobility_plot.set_ylabel("Count") collaboration_results = results.loc[:, ['Verbal Collaboration', 'Physical Collaboration', 'Morale Collaboration']] collaboration_plot = collaboration_results.plot(ax=axes[2]) collaboration_plot.set_title("Human Collaboration") collaboration_plot.set_xlabel("Simulation Step") collaboration_plot.set_ylabel("Successful Attempts") collaboration_plot.set_ylim(ymin=0) timestr = time.strftime("%Y%m%d-%H%M%S") plt.suptitle("Percentage Collaborating: " + str(self.collaboration_percentage) + "%, Number of Human Agents: " + str(self.human_count), fontsize=16) plt.savefig(OUTPUT_DIR + "/model_graphs/" + timestr + ".png") plt.close(fig) # Starts a fire at a random piece of furniture with file_probability chance def start_fire(self): rand = random.random() if rand < self.fire_probability: fire_furniture = random.choice(self.furniture_list) fire = Fire(fire_furniture, self) self.grid.place_agent(fire, fire_furniture) self.schedule.add(fire) self.fire_started = True print("Fire started at:", fire_furniture) def step(self): """ Advance the model by one step. """ self.schedule.step() # If there's no fire yet, attempt to start one if not self.fire_started: self.start_fire() self.datacollector.collect(self) # If no more agents are alive, stop the model and collect the results if self.count_human_status(self, Human.Status.ALIVE) == 0: self.running = False if self.save_plots: self.save_figures() @staticmethod def count_human_collaboration(model, collaboration_type): """ Helper method to count the number of collaborations performed by Human agents in the model """ count = 0 for agent in model.schedule.agents: if isinstance(agent, Human): if collaboration_type == Human.Action.VERBAL_SUPPORT: count += agent.get_verbal_collaboration_count() elif collaboration_type == Human.Action.MORALE_SUPPORT: count += agent.get_morale_collaboration_count() elif collaboration_type == Human.Action.PHYSICAL_SUPPORT: count += agent.get_physical_collaboration_count() return count @staticmethod def count_human_status(model, status): """ Helper method to count the status of Human agents in the model """ count = 0 for agent in model.schedule.agents: if isinstance(agent, Human): if agent.get_status() == status: count += 1 return count @staticmethod def count_human_mobility(model, mobility): """ Helper method to count the mobility of Human agents in the model """ count = 0 for agent in model.schedule.agents: if isinstance(agent, Human): if agent.get_mobility() == mobility: count += 1 return count
class Themepark(Model): def __init__(self, N_attr, N_cust, width, height, strategy, theme, max_time, weight, adaptive): """ Args: N_attr (int): the amount of attractions in the theme park N_cust (int): the amout of customers in the theme park width (int): the width of the theme park grid height (int): the height of the theme park grid strategy (str): the strategy of this run (random agents, adaptive agents or adaptive agents with noise) theme (str): the setup of the park (circle, random or clustered) max_time (int): the number of time steps the park will do in one run weight (float): if the customer agents are non-adaptive, this is the strategy they are using adaptive (bool): whether customer agents are able to switch strategies """ self.theme = theme self.max_time = max_time self.N_attr = N_attr self.penalty_per = PENALTY_PERCENTAGE self.weight = weight self.adaptive = adaptive self.strategies = STRATEGIES self.happinesses = [] self.N_attr = N_attr self.N_cust = N_cust self.width = width self.height = height self.total_steps = 0 self.cust_ids = N_cust self.strategy = strategy self.grid = MultiGrid(width, height, torus=False) self.schedule = BaseScheduler(self) self.schedule_Attraction = BaseScheduler(self) self.schedule_Customer = BaseScheduler(self) # Cluster or circle coordinates if self.theme == "cluster": self.x_list, self.y_list, self.positions = xlist, ylist, positions elif self.theme == "circle": self.x_list, self.y_list, self.positions = get_attraction_coordinates( width, height, N_attr, "circle") # keeps up the current time self.totalTOTAL = 0 # add attractions to park self.attractions = self.make_attractions() self.attraction_history = self.make_attr_hist() self.running = True self.data_dict = {} # keep up a history of the strategies self.hist_random_strat = [] self.hist_close_strat = [] # keep up a history of the occupation of the rides self.all_rides_list = [] # distribution of strategies throughout population self.strategy_composition = self.make_strategy_composition() # add customers to park self.customers = self.add_customers(self.N_cust) # keep up park score throughout time self.park_score = [] for attraction in self.get_attractions(): self.data_dict[attraction.unique_id] = ({ "id": attraction.unique_id, "length": attraction.attraction_duration, "waiting_list": [] }) # datacollector for the visualisation of the data if self.strategy == "Random_test_4": self.datacollector = DataCollector({ "Random": lambda m: self.strategy_counter(self.strategies[0]), "0.00": lambda m: self.strategy_counter(self.strategies[1]), "0.25": lambda m: self.strategy_counter(self.strategies[2]), "0.50": lambda m: self.strategy_counter(self.strategies[3]), "0.75": lambda m: self.strategy_counter(self.strategies[4]), "1.00": lambda m: self.strategy_counter(self.strategies[5]), }) elif self.strategy == "Random": self.datacollector = DataCollector( {"Random": lambda m: self.N_cust}) else: self.datacollector = DataCollector({ "0.00": lambda m: self.strategy_counter(self.strategies[0]), "0.25": lambda m: self.strategy_counter(self.strategies[1]), "0.50": lambda m: self.strategy_counter(self.strategies[2]), "0.75": lambda m: self.strategy_counter(self.strategies[3]), "1.00": lambda m: self.strategy_counter(self.strategies[4]), }) self.datacollector2 = DataCollector( {"score": lambda m: self.make_score()}) def make_score(self): """ Calculates and returns an efficiency score for the enire theme park. """ # calculates the ideal distribution of customers over the attractions per attraction ideal = {} cust_in_row = 0 for i in range(len(self.get_attractions())): ideal[i] = self.N_cust / self.N_attr cust_in_row += self.get_attractions()[i].N_current_cust # calculates the difference between the ideal and the real situation tot_difference = 0 for i in range(len(self.get_attractions())): difference = abs(cust_in_row / self.N_attr - self.get_attractions()[i].N_current_cust) tot_difference += difference # the fraction of customers that is not optimally distributed fraction_not_right = (tot_difference / self.N_cust) # add a penalty by multiplying by the fraction of people currently in a line score = abs(1 - (fraction_not_right)) * cust_in_row / self.N_cust return score def make_attr_hist(self): """ Make history of attractions that are visited for each customer. """ attraction_history = {} for attraction in self.get_attractions(): attraction_history[attraction] = [0] * (self.max_time + 1) return attraction_history def strategy_counter(self, strategy): """ Input is a strategy, for example "0.25" or "Random", output is the number of strategies are adopted at a current time step. """ for attraction_pos in self.positions: counter = 0 for agent in self.customers: if agent.weight == strategy: counter += 1 return counter def make_strategy_composition(self): """ Make a composition of all strategies over the entire theme park. Returns a dictionary with strategies as keys and the fraction of people using this strategy as value. """ # if this is a run with adaptive agents and noise if self.strategy == "Random_test_4": self.strategies = ["Random_test_4", 0.0, 0.25, 0.50, 0.75, 1.0] # make dictionary with fractions (values can be ignored!) dict = { self.strategies[0]: 0, self.strategies[1]: 0.20, self.strategies[2]: 0.20, self.strategies[3]: 0.20, self.strategies[4]: 0.20, self.strategies[5]: 0.20 } composition_list = [] for i in range(len(self.strategies)): if i == 0: dict[self.strategies[i]] = FRACTION_RANDOM continue else: # choose a random number composition_list.append(random.randint(0, 100)) sum_comp = sum(composition_list) sum_comp = sum_comp - sum_comp * FRACTION_RANDOM for i in range(len(self.strategies)): if i == 0: continue else: # determine the fraction of customer agents with this strategy dict[self.strategies[i]] = composition_list[i - 1] / sum_comp # runs without noise else: # make dictionary with fractions (values can be ignored!) dict = { self.strategies[0]: 0.20, self.strategies[1]: 0.20, self.strategies[2]: 0.20, self.strategies[3]: 0.20, self.strategies[4]: 0.20 } composition_list = [] for i in range(len(self.strategies)): # choose a random number composition_list.append(random.randint(0, 100)) sum_comp = sum(composition_list) for i in range(len(self.strategies)): # determine the fraction of agents with this strategy dict[self.strategies[i]] = composition_list[i - 1] / sum_comp return dict def make_attractions(self): """ Initialize attractions on fixed positions, defined in the global variables x_list and y_list. Returns a dictionary of attractions """ attractions = {} for i in range(self.N_attr): pos = (self.x_list[i], self.y_list[i]) # place attraction if grid cell is empty if self.grid.is_cell_empty(pos): name = str(i) a = Attraction(i, self, pos, name) attractions[i] = a self.schedule_Attraction.add(a) self.grid.place_agent(a, pos) return attractions def get_attractions(self): """ Return a list with all attractions. """ agents = self.grid.get_neighbors(mid_point, moore=True, radius=RADIUS, include_center=True) attractions = [] for agent in agents: if type(agent) == Attraction: attractions.append(agent) return attractions def add_customers(self, N_cust, added=False): """ Initialize customers on random positions. Returns a list of all customers """ # a list of weights of which the indices correspond to the id of the agent # to who this weight is given weights_list = [] # Adaptive strategy if self.adaptive is True: # Decide weights for every customer for j in self.strategy_composition.keys(): for i in range(round(N_cust * self.strategy_composition[j])): weights_list.append(j) # Add weights for the random strategy if len(weights_list) < self.N_cust: rand = random.choice(self.strategies) weights_list.append(rand) elif len(weights_list) > self.N_cust: rand = random.choice(weights_list) weights_list.remove(rand) else: if self.strategy is not "Random": for i in range(round(N_cust)): print(self.weight) weights_list.append(self.weight) cust_list = [] for i in range(N_cust): # Get random location within grid height and width pos_temp = [ random.randint(0, WIDTH - 1), random.randint(0, HEIGHT - 1) ] rand_x, rand_y = pos_temp[0], pos_temp[1] pos = (rand_x, rand_y) if added is True: i = self.cust_ids if self.strategy == "Random_test_4": if weights_list[i] == "Random_test_4": strategy = "Random_test_4" else: strategy = "Closest_by" else: strategy = self.strategy if weights_list == []: weight = None else: weight = weights_list[i] # make customer a = Customer(i, self, pos, strategy, weight, self.adaptive) self.schedule_Customer.add(a) self.grid.place_agent(a, pos) cust_list.append(a) return cust_list def calculate_people(self): """ Calculate how many customers are in which attraction. Returns a list of which the indices correspond to the ids of the atttraction """ counter_total = {} # loop through attractions for attraction_pos in self.positions: agents = self.grid.get_neighbors(attraction_pos, moore=True, radius=0, include_center=True) counter = 0 # find customers in this attraction for agent in agents: if type(agent) is Customer: counter += 1 else: attraction = agent # update the amount of customers in this attraction attraction.N_current_cust = counter counter_total[attraction.unique_id] = counter return list(counter_total.values()) def calc_waiting_time(self): """ Return a dictionary of watingtimes for every attraction """ counter_total = {} attractions = self.get_attractions() for attraction in attractions: counter_total[ attraction.unique_id] = attraction.current_waitingtime return counter_total def calculate_people_sorted(self): """ Calculate how many customers are in which attraction. Returns a dictionary with attraction-ids as keys and customers in line as values. """ counter_total = {} # loop through attractions for attraction_pos in self.positions: agents = self.grid.get_neighbors(attraction_pos, moore=True, radius=0, include_center=True) counter = 0 # find customers in this attraction for agent in agents: if type(agent) is Customer: counter += 1 else: attraction = agent # update the amount of customers in this attraction attraction.N_current_cust = counter self.attraction_history[attraction][self.totalTOTAL] = counter counter_total[attraction.unique_id] = counter return counter_total def get_strategy_history(self): """ Update history with how many customers chose which strategy """ customers = self.get_customers() randomstrat, closebystrat = 0, 0 for customer in customers: if customer.strategy == "Random" or customer.strategy == "Random_test_4": randomstrat += 1 elif customer.strategy == "Closest_by": closebystrat += 1 self.hist_random_strat.append(randomstrat) self.hist_close_strat.append(closebystrat) def get_customers(self): """Return a list of all customers in the theme park.""" agents = self.grid.get_neighbors(mid_point, moore=True, radius=RADIUS, include_center=True) customers = [] # Count customer agents for agent in agents: if type(agent) == Customer: customers.append(agent) return customers def get_data_customers(self): """ Return dictionary with data of customers """ data = {} agents = self.grid.get_neighbors(mid_point, moore=True, radius=RADIUS, include_center=True) for agent in agents: if type(agent) is Customer: data[agent.unique_id] = { "totalwaited": agent.total_ever_waited, "visited_attractions": agent.nmbr_attractions, "strategy": agent.strategy, "swapped_strat": agent.strategy_swap_hist } return data def calc_hapiness(self): """ Calculate mean hapiness of all customers, based on: - How many rides were taken - Number of times in the same attraction - Total waiting time Returns the mean happiness of all customers """ customers = self.get_customers() scores = [] for customer in customers: history = customer.history values = list(history.values()) total_rides = sum(values) if total_rides != 0: scores.append(total_rides / self.N_attr - self.totalTOTAL / customer.total_ever_waited) else: return None scores = np.interp(scores, (min(scores), max(scores)), (1, 10)) return np.mean(scores) def get_history_list(self): """ Return a dictionary of the history of visited attraction for each customer. """ customers = self.get_customers() histories = {} for customer in customers: history = customer.history values = list(history.values()) histories[customer.unique_id] = values return histories def final(self): """ Return and save data at the end of the run.""" hist_list = [] agents = self.grid.get_neighbors(mid_point, moore=True, radius=RADIUS, include_center=True) attractions = self.get_attractions() # Make a list for the fraction of occupied rides at all time steps self.all_rides_list = [0] * len(attractions[0].in_attraction_list) for attraction in attractions: for i in range(len(attraction.in_attraction_list)): self.all_rides_list[i] += attraction.in_attraction_list[i] for i in range(len(self.all_rides_list)): self.all_rides_list[i] /= self.N_attr cust_data = self.get_data_customers() for agent in agents: if type(agent) is Customer: sum_attr = sum(agent.history.values()) if sum_attr > 0: hist_list.append(agent.strategy_swap_hist) else: hist_list.append(agent.strategy_swap_hist) histories = self.get_history_list() # save data try: pickle.dump(self.datacollector.get_model_vars_dataframe(), open("../data/strategy_history.p", 'wb')) pickle.dump(self.datacollector2.get_model_vars_dataframe(), open("../data/eff_score_history.p", 'wb')) pickle.dump(cust_data, open("../data/customers.p", 'wb')) pickle.dump(self.park_score[-1], open("../data/park_score.p", "wb")) pickle.dump(self.happinesses, open("../data/hapiness.p", "wb")) pickle.dump(histories, open("../data/cust_history.p", 'wb')) pickle.dump(self.all_rides_list, open("../data/all_rides.p", "wb")) except: pickle.dump(self.datacollector.get_model_vars_dataframe(), open("data/strategy_history.p", 'wb')) pickle.dump(self.datacollector2.get_model_vars_dataframe(), open("data/eff_score_history.p", 'wb')) pickle.dump(cust_data, open("data/customers.p", 'wb')) pickle.dump(self.park_score[-1], open("data/park_score.p", "wb")) pickle.dump(self.happinesses, open("data/hapiness.p", "wb")) pickle.dump(histories, open("data/cust_history.p", 'wb')) pickle.dump(self.all_rides_list, open("data/all_rides.p", "wb")) print() print("RUN HAS ENDED") print() def save_data(self): """Save data of all attractions and customers.""" # Get info waitinglines = self.calc_waiting_time() for i in range(len(self.attractions)): self.data_dict[i]["waiting_list"].append(waitinglines.get(i)) self.park_score.append(sum(waitinglines.values())) self.happinesses.append(self.calc_hapiness()) def step(self): """Advance the model by one step.""" if self.totalTOTAL < self.max_time: self.totalTOTAL += 1 self.schedule.step() # Collect data for every step self.datacollector.collect(self) self.datacollector2.collect(self) # Step for both attraction and customer self.schedule_Attraction.step() self.schedule_Customer.step() self.total_steps += 1 # Save data and update strategy history self.save_data() self.get_strategy_history() else: for key in self.attraction_history.keys(): y = self.attraction_history[key] x = list(range(0, self.max_time)) self.final()
class InfectionModel(Model): """A model for infection spread.""" def __init__(self, human_count, random_spawn, save_plots, floor_plan_file="floorplan_1.txt", N=30, width=10, height=10, ptrans=0.5, progression_period=3, progression_sd=2, death_rate=0.0193, recovery_days=21, recovery_sd=7): # Load floorplan # floorplan = np.genfromtxt(path.join("infection_spread/floorplans/", floor_plan_file)) with open( os.path.join("infection_spread/floorplans/", floor_plan_file), "rt") as f: floorplan = np.matrix( [line.strip().split() for line in f.readlines()]) # Rotate the floorplan so it's interpreted as seen in the text file floorplan = np.rot90(floorplan, 3) # Check what dimension our floorplan is width, height = np.shape(floorplan) # Init params self.num_agents = N self.initial_outbreak_size = 1 self.recovery_days = recovery_days self.recovery_sd = recovery_sd self.ptrans = ptrans self.death_rate = death_rate self.running = True self.dead_agents = [] self.width = width self.height = height self.human_count = human_count # Set up model objects self.schedule = RandomActivation(self) self.grid = MultiGrid(height, width, torus=False) # Used to easily see if a location is an Exit or Door, since this needs to be done a lot self.exit_list = [] self.door_list = [] # If random spawn is false, spawn_list will contain the list of possible spawn points according to the floorplan self.random_spawn = random_spawn self.spawn_list = [] # Load floorplan objects for (x, y), value in np.ndenumerate(floorplan): value = str(value) floor_object = None if value == "W": floor_object = Wall((x, y), self) elif value == "E": floor_object = Exit((x, y), self) self.exit_list.append((x, y)) self.door_list.append((x, y)) # Add exits to doors as well elif value == "D": floor_object = Door((x, y), self) self.door_list.append((x, y)) elif value == "S": self.spawn_list.append((x, y)) if floor_object: self.grid.place_agent(floor_object, (x, y)) self.schedule.add(floor_object) # Create a graph of traversable routes, used by agents for pathing self.graph = nx.Graph() for agents, x, y in self.grid.coord_iter(): pos = (x, y) # If the location is empty, or a door if not agents or any(isinstance(agent, Door) for agent in agents): neighbors = self.grid.get_neighborhood(pos, moore=True, include_center=True, radius=1) for neighbor in neighbors: # If there is contents at this location and they are not Doors or Exits, skip them if not self.grid.is_cell_empty( neighbor) and neighbor not in self.door_list: continue self.graph.add_edge(pos, neighbor) # Collects statistics from our model run self.datacollector = DataCollector({ "Susceptible": lambda m: self.count_human_status(m, Human.State.SUSCEPTIBLE), "Infected": lambda m: self.count_human_status(m, Human.State.INFECTED), "Removed": lambda m: self.count_human_status(m, Human.State.REMOVED) }) # Start placing human agents # for i in range(0, self.human_count): # if self.random_spawn: # Place human agents randomly # pos = self.grid.find_empty() # else: # Place human agents at specified spawn locations # pos = random.choice(self.spawn_list) #if pos: # Create a random human # health = random.randint(self.MIN_HEALTH * 100, self.MAX_HEALTH * 100) / 100 # speed = random.randint(self.MIN_SPEED, self.MAX_SPEED) for i in range(0, self.num_agents): a = Human(unique_id=i, model=self) self.schedule.add(a) # Add the agent to a random grid cell # x = self.random.randrange(self.grid.width) # y = self.random.randrange(self.grid.height) # self.grid.place_agent(a, (x, y)) if self.random_spawn: # Place human agents randomly pos = self.grid.find_empty() else: # Place human agents at specified spawn locations pos = random.choice(self.spawn_list) self.grid.place_agent(a, pos) #make some agents infected at start infected = np.random.choice([0, 1], 1, p=[0.98, 0.02]) if infected == 1: a.state = State.INFECTED a.recovery_time = self.get_recovery_time() self.datacollector = DataCollector( #model_reporters={"Gini": compute_gini}, agent_reporters={"State": "state"}) def get_recovery_time(self): return int( self.random.normalvariate(self.recovery_days, self.recovery_sd)) def step(self): """ Advance the model by one step. """ self.schedule.step() self.datacollector.collect(self)
class Covid(Model): """ Model class for the Covid infection model. """ def __init__(self, density, initial_infected, infection_rate, min_infected, max_infected, mean_infected, min_exposed, max_exposed, mean_exposed, day_steps, day_isolation, detection_rate, width=20): """ """ # square grid height = width self.height = height self.width = width self.density = density self.initial_infected = initial_infected self.infection_rate = infection_rate self.detection_rate = detection_rate self.day_steps = day_steps self.min_exposed = min_exposed * self.day_steps self.max_exposed = max_exposed * self.day_steps self.mean_exposed = mean_exposed * self.day_steps self.min_infected = min_infected * self.day_steps self.max_infected = max_infected * self.day_steps self.mean_infected = mean_infected * self.day_steps self.day_isolation = day_isolation * self.day_steps self.schedule = RandomActivation(self) self.grid = MultiGrid(width, height, torus=True) self.infected = 0 self.exposed = 0 self.susceptible = 0 self.removed = 0 self.contact = 0 self.cuminfected = 0 self.isolated = 0 self.stats = { "infected": [], "exposed": [], "susceptible": [], "removed": [], "isolated": [] } self.datacollector = DataCollector( # Model-level count { "contact": "contact", "infected": "infected", "cuminfected": "cuminfected", "exposed": "exposed", "susceptible": "susceptible", "removed": "removed", "isolated": "isolated", "stats": "stats" }, # 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) num_agents = 0 num_infected = 0 while num_agents < self.density: #for cell in self.grid.coord_iter(): #x = cell[1] #y = cell[2] # obtaining non-empty cell x = int(self.random.uniform(0, width)) y = int(self.random.uniform(0, height)) while not self.grid.is_cell_empty((x, y)): x = int(self.random.uniform(0, width)) y = int(self.random.uniform(0, height)) if num_agents < self.density and self.random.random() < 0.2: if num_infected < self.initial_infected: agent_type = Infected() num_infected += 1 # generate typical infected lifespan from normal distribution ls = self.random.uniform(self.min_infected, self.max_infected) agent_type.setLifespan(ls) agent_type.set_detected( self.random.uniform(0, 1) < self.detection_rate) else: agent_type = Susceptible() agent = CovidAgent((x, y), self, agent_type) self.grid.place_agent(agent, (x, y)) self.schedule.add(agent) num_agents += 1 #print(str(num_agents)+" agents finally.") self.running = True #self.datacollector.collect(self) def step(self): """ Run one step of the model. If All agents are happy, halt the model. """ # Reset counters self.infected = 0 self.exposed = 0 self.susceptible = 0 self.removed = 0 self.isolated = 0 self.schedule.step() # compute average contact per agent total = 0 for cell in self.grid.coord_iter(): content, x, y = cell if content: for c in content: total += len(c.contact) if isinstance(c.d_state, Infected): self.infected += 1 elif isinstance(c.d_state, Exposed): self.exposed += 1 elif isinstance(c.d_state, Susceptible): self.susceptible += 1 elif isinstance(c.d_state, Removed): self.removed += 1 if not c.move: #print("isolated") self.isolated += 1 self.contact = total / self.schedule.get_agent_count() self.stats["infected"].append(self.infected) self.stats["exposed"].append(self.exposed) self.stats["susceptible"].append(self.susceptible) self.stats["removed"].append(self.removed) self.stats["isolated"].append(self.isolated) # collect data self.datacollector.collect(self) if self.infected + self.exposed == 0: self.running = False if self.schedule.steps / self.day_steps > 180: self.running = False