class Model(Model): def __init__(self, N, B, T, Treg, width, height): self.num_myelin = N * 8 self.num_agents = N + B + T + Treg + self.num_myelin self.num_neurons = N self.num_myelin = 4 self.num_limfocytB = B self.num_active_B = 0 self.num_infected_B = 0 self.num_limfocytT = T self.num_activeT = 0 self.num_limfocytTreg = Treg self.grid = MultiGrid(width, height, True) self.schedule = RandomActivation(self) self.available_ids = set() self.dead_agents = set() self.new_agents = set() self.max_id = 0 self.step_count = 1 self.cytokina = 0 self.cytokina_prev = 0 self.sum = 0 self.B = 0 self.a = 0.80 self.Ymax = 100 open('new_and_dead.txt', 'w').close() # Create agents neuron_positions = [[3, 3], [3, 10], [3, 20], [3, 27], [10, 3], [10, 10], [10, 20], [10, 27], [19, 3], [19, 10], [19, 20], [19, 27], [26, 3], [26, 10], [26, 20], [26, 27], [14, 15]] for i in range(self.num_neurons): a = Neuron(i, self, "Neuron") self.schedule.add(a) #Add 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)) pos = neuron_positions[i] self.grid.place_agent(a, (pos[0], pos[1])) cells = self.grid.get_neighborhood(a.pos, True, False, 1) id = self.num_agents - i * 8 for cell in cells: m = Myelin(id, self, "Myelin") self.schedule.add(m) self.grid.place_agent(m, cell) id -= 1 #dodawanie różnych typów agentów zgodnie z ich liczbą podaną przy inicjacji modelu for i in range(self.num_limfocytB): a = LimfocytB(i + self.num_neurons, self, "LimfocytB") self.schedule.add(a) #Add 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)) for i in range(self.num_limfocytT): a = LimfocytT(i + N + B, self, "LimfocytT") self.schedule.add(a) #Add 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)) for i in range(self.num_limfocytTreg): a = LimfocytTreg(i + N + B + T, self, "LimfocytTreg") self.schedule.add(a) #Add 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)) self.max_id = self.num_agents - 1 self.datacollector_population = DataCollector( model_reporters={"Populacja": compute_population}) self.datacollector_T_population = DataCollector( model_reporters={"Populacja Limfocytów T": T_population}) #self.datacollector_T_precentage=DataCollector( #model_reporters={"Precentage Limfocyt T": T_popualtion_precentage}) self.datacollector_B_population = DataCollector( model_reporters={"Populacja Limfocytów B": B_population}) self.datacollector_Treg_population = DataCollector( model_reporters={"Populacja Limfocytów Treg": Treg_population}) self.datacollector_B_active_population = DataCollector( model_reporters={ "Populacja Aktywnych Limfocytów B": B_activated_population }) self.datacollector_T_active_population = DataCollector( model_reporters={ "Populacja Aktywnych Limfocytów T": T_activated_population }) self.datacollector_B_infected_population = DataCollector( model_reporters={ "Populacja Zainfekowanych Limfocytów B": B_infected_population }) self.datacollector_myelin_population = DataCollector( model_reporters={ "Populacja osłonek mielinowych": myelin_population }) self.datacollector_myelin_healths = DataCollector( model_reporters={ "Suma punktów życia osłonek mielinowych": myelin_healths }) def step(self): #print("self running: "+str(self.running())) self.schedule.step() self.datacollector_population.collect(self) self.datacollector_T_population.collect(self) #self.datacollector_T_precentage.collect(self) self.datacollector_B_population.collect(self) self.datacollector_Treg_population.collect(self) self.datacollector_B_active_population.collect(self) self.datacollector_T_active_population.collect(self) self.datacollector_B_infected_population.collect(self) self.datacollector_myelin_population.collect(self) self.datacollector_myelin_healths.collect(self) self.adding_removing() self.datacollector_myelin_healths.get_model_vars_dataframe().to_csv( r'Data/myelin_healths25.txt', sep=' ', mode='w') self.datacollector_T_population.get_model_vars_dataframe().to_csv( r'Data/T_population25.txt', sep=' ', mode='w') self.datacollector_B_population.get_model_vars_dataframe().to_csv( r'Data/B_population25.txt', sep=' ', mode='w') self.datacollector_Treg_population.get_model_vars_dataframe().to_csv( r'Data/Treg_population25.txt', sep=' ', mode='w') self.datacollector_B_active_population.get_model_vars_dataframe( ).to_csv(r'Data/B_active_population25.txt', sep=' ', mode='w') self.datacollector_T_active_population.get_model_vars_dataframe( ).to_csv(r'Data/T_active_population25.txt', sep=' ', mode='w') self.datacollector_B_infected_population.get_model_vars_dataframe( ).to_csv(r'Data/B_infected_population25.txt', sep=' ', mode='w') print("Liczba agentów: " + str(self.num_agents)) print("MaxID: " + str(self.max_id)) self.cytokina = max( min((self.B + self.cytokina_prev), self.Ymax) * self.a, 0) print("Cytokina " + str(self.cytokina)) print("Cytokina_prev " + str(self.cytokina_prev)) f = open("agents.txt", 'a') f.write("======Step : " + str(self.step_count) + "\n") for agent in self.schedule.agents: f.write("Agent: " + str(agent.type) + " " + str(agent.unique_id) + str(agent.pos) + "\n") f.close() self.cytokina_prev = self.cytokina self.B = 0 def running(self): self.step() def adding_removing( self): #funckja odpowiedzialna za dodawanie i usuwanie agentów #print("AddingRemoving") f = open("new_and_dead.txt", 'a') f.write("Step " + str(self.step_count) + "\n") f.write("======Dead agents======: " + "\n") for d in self.dead_agents: try: self.schedule.remove(d) self.num_agents -= 1 self.available_ids.add(d.unique_id) except KeyError: continue try: self.grid._remove_agent(d.pos, d) except KeyError: continue f.write(str(d.unique_id) + " " + d.type + "\n") #if d.type=="AktywowanyLimfocytT": # self.cytokina-=1 self.dead_agents.clear() f.write("======New Agents=====: " + "\n") for n in self.new_agents: self.schedule.add(n) self.num_agents += 1 self.grid.place_agent(n, n.pos) if n.unique_id in self.available_ids: self.available_ids.remove(n.unique_id) f.write(str(n.unique_id) + " " + n.type + "\n") #if n.type=="AktywowanyLimfocytT": # self.cytokina+=1 self.new_agents.clear() m = 1 n = 0 for agent in self.schedule.agents: if agent.unique_id > m: m = agent.unique_id if (agent.type == "LimfocytT") or (agent.type == "AktywowanyLimfocytT"): n += 1 self.max_id = m self.num_limfocytT = 0 self.deficiencies() f.close() def deficiencies(self): n = B_population(self) if n == 0: if len(self.available_ids) == 0: self.max_id += 1 id = self.max_id else: id = min(self.available_ids) self.available_ids.remove(id) agent = LimfocytB(id, self, "LimfocytB") self.schedule.add(agent) x = self.random.randrange(self.grid.width) y = self.random.randrange(self.grid.height) self.grid.place_agent(agent, (x, y)) self.num_agents += 1 n = T_population(self) if n == 0: for i in range(10): if len(self.available_ids) == 0: self.max_id += 1 id = self.max_id else: id = min(self.available_ids) self.available_ids.remove(id) agent = LimfocytB(id, self, "LimfocytT") self.schedule.add(agent) x = self.random.randrange(self.grid.width) y = self.random.randrange(self.grid.height) self.grid.place_agent(agent, (x, y)) self.num_agents += 1 n = Treg_population(self) if n == 0: if len(self.available_ids) == 0: self.max_id += 1 id = self.max_id else: id = min(self.available_ids) self.available_ids.remove(id) agent = LimfocytB(id, self, "LimfocytTreg") self.schedule.add(agent) x = self.random.randrange(self.grid.width) y = self.random.randrange(self.grid.height) self.grid.place_agent(agent, (x, y)) self.num_agents += 1
class LandModel(Model): """ Main model """ def __init__(self, percentage_buyers, # Percentage of buyers to be added acording to the available land percentage_high_income, #Percentage that are high income rich_market_reach, # The amount of properties the rich can bid poor_market_reach, # The amount of properties the poor can bid base_price, # The land base price base_income, # The base income for all buyers rich_poor_std, #Standard deviation for the rich and poor num_cities, # The number of cities b, # Constant for the wtp formula urbanization_over_rural_roductivity, # Constant for the probability of selling size, # tuple: (width, height) alpha = 0.5,# The alpha parameter (preference) amenities = "uniform", #The amenities rural_productivity = "uniform", # The rural productivity buyer_mode = cons.BID_SCHEME.BEST, max_epochs = 10, #number of epochs max_urbanization = np.inf # Maximum number of urbanization units ): position = "CENTRAL" #print('') #print('Rich: ' + str(rich_market_reach) + ' Poor: ' + str(poor_market_reach)) #Variables for batch run self.num_epochs = 0 self.max_epochs = max_epochs self.max_urbanization = max_urbanization self.running = True #Scheduler self.schedule = BaseScheduler(self) #Assigns variables to the model self.base_price = base_price self.base_income = base_income self.rich_poor_std = rich_poor_std self.rich_market_reach = rich_market_reach self.poor_market_reach = poor_market_reach self.b = b self.w2 = urbanization_over_rural_roductivity self.w1 = 1 - self.w2 self.epyslon = 0 self.alpha = alpha self.buyer_mode = buyer_mode #Sets up the grid #Size of Grid self.width = size[0] self.height = size[1] self.grid = MultiGrid(self.width, self.height, True) # Multigrid - Agents can share a cell #Assign the shapes self.grid_shape = (self.width, self.height) #Distribution variables self.amenities = self.get_distribution(amenities) self.rural_productivity = self.get_distribution(rural_productivity) #Starts the patches as an empty matix self.patches = np.empty((self.width, self.height), dtype = object) #Invokes the city generator # Checks if will import from raster if str(num_cities).upper() == 'RASTER': centers, city_fun = CityGenerator.import_from_raster(self.grid_shape) else: # Handles the city creation (at random) and the corresponding centers centers, city_fun = CityGenerator.make_cities_fun(self.grid_shape, num_cities = num_cities, position = position) self.city_centers = centers #Calculates max city distance (for the city proximity function) self.max_city_distance = self.get_max_city_distance() #Starts land patches and city pathces (both are sets to guarantee O(1) lookup) self.land_patches = set() self.city_patches = set() #Iterates over each possible patch and assigns city or land for index in list(itertools.product(range(self.width), range(self.height))): patch = LandPatch("land_patch_" + str(index), self) patch.type = city_fun(index) if(patch.type == cons.LAND_TYPES.CITY): self.city_patches.add(patch) patch.convert_to_city() else: self.land_patches.add(patch) patch.convert_to_land() self.grid.place_agent(patch, index) self.patches[index] = patch patch.set_properties() # Initializes patch #The number of sellers will be the number of land patches num_sellers = len(self.land_patches) self.percentage_buyers = percentage_buyers if(percentage_buyers <= 0 or percentage_buyers > 100): raise ValueError('Percentage of buyers is incorrect: ' + str(percentage_buyers)) # Calculates the number of buyers self.percentage_high_income = percentage_high_income self.num_buyers = np.round((self.percentage_buyers/100)*len(self.land_patches)) # Sets up the number of poor and rich buyers self.num_rich_buyers = int(self.num_buyers*self.percentage_high_income/100) self.num_poor_buyers = int(self.num_buyers*(100- self.percentage_high_income)/100) #Number of Agents self.num_sellers = num_sellers self.num_buyers = self.num_rich_buyers + self.num_poor_buyers self.num_agents = self.num_sellers + self.num_buyers self.buyers = set() self.sellers = set() #To remove # At the end of each iteration will remove the sellers who sold self.to_remove = [] # adds the sellers (one for each land patch) added_sellers = 0 for pat in self.land_patches: seller = Seller("seller_" + str(added_sellers), self, pat) self.schedule.add(seller) #Adds the seller self.grid.place_agent(seller, pat.pos) self.sellers.add(seller) added_sellers += 1 # Adds the buyers self.add_rich_buyers(self.num_rich_buyers) self.add_poor_buyers(self.num_poor_buyers) # The data collector # For plotting oprions self.current_bids = [] self.datacollector = DataCollector( model_reporters={"Amenities": get_mean_amenities}) def step(self): """ Method that simulates the step of an epoch """ #Scehdule #print('Step ' + str(self.num_epochs)) #Calculates the sellers that will sell market = set() for seller in self.sellers: if(seller.will_sell()): market.add(seller) if(len(market) == 0): print('Nobody wants to sell') #All the buyer make their bids for buyer in self.buyers: buyer.make_bids(market, self.buyer_mode) #Asjust Epsylon self.epyslon = (len(self.buyers) - len(self.sellers))/(len(self.buyers) + len(self.sellers)) #Randomly, buyers and sellers interact sellers = random.sample(self.sellers, len(self.sellers)) for seller in sellers: sold = seller.sell() if(sold): #Removes seller self.grid._remove_agent(seller.pos, seller) self.sellers.remove(seller) self.current_bids = [] #removes all buyers self.remove_all_buyers() #Updates the number of buyers for next epoch self.num_buyers = np.round((self.percentage_buyers/100)*len(self.land_patches)) # Sets up the number of poor and rich buyers self.num_rich_buyers = int(self.num_buyers*self.percentage_high_income/100) self.num_poor_buyers = int(self.num_buyers*(100- self.percentage_high_income)/100) self.num_buyers = self.num_rich_buyers + self.num_poor_buyers #Adds the new generation self.add_rich_buyers(self.num_rich_buyers) self.add_poor_buyers(self.num_poor_buyers) #Collects data self.datacollector.collect(self) #Adjust progress variables (for batch process) self.num_epochs += 1 if(self.num_epochs == self.max_epochs or self.get_num_patches() == 0): self.running = False #Stops the process if the maximum urbanization limit is exceeded if(len(self.city_patches) >= self.max_urbanization): print(self.num_epochs) self.running = False def get_max_city_distance(self): """ Calculates the max city distance available in the greed (recall there can be multiple cities) """ indices = list(itertools.product(range(self.width),range(self.height))) positions = np.array(indices) centers = np.array(self.city_centers) dist_centers = metrics.pairwise.euclidean_distances(positions,centers) dist_centers = np.min(dist_centers, axis = 1) return(np.max(dist_centers)) def get_available_pos(self): """ Gets an available position (so agent don't end up in a city patch) Was design for when the agents bought around them. """ if(self.land_patches): land_patch = random.sample(self.land_patches,1)[0] return(land_patch.pos) return(None) def get_available_positions(self, k, replace = False): choices = np.random.choice(list(self.land_patches), size = k, replace = replace) return([land_patch.pos for land_patch in choices]) def get_num_patches(self): return(len(self.land_patches)) def remove_all_buyers(self): """ Removes all buyers from the model. At the end of every epoch, this method is called """ for agent in self.buyers: self.grid._remove_agent(agent.pos, agent) self.schedule.remove(agent) self.buyers = set() def add_rich_buyers(self, num_rich_buyers): """ Add rich buyers to the grid """ indices = self.get_available_positions(num_rich_buyers) for i in range(num_rich_buyers): income = max(0,(self.base_income + np.abs(np.random.normal(loc = 0, scale = self.rich_poor_std)))) buyer = Buyer("buyer_rich_" + str(i), self, income = income, market_reach = self.rich_market_reach, type = cons.AGENT_TYPES.RICH) self.schedule.add(buyer) #Gets an available position index = indices[i] #Adds the buyer self.grid.place_agent(buyer, index) self.buyers.add(buyer) def add_poor_buyers(self, num_poor_buyers): """ Add poor buyers to the grid """ indices = self.get_available_positions(num_poor_buyers) for i in range(num_poor_buyers): income = max(0,(self.base_income - np.abs(np.random.normal(loc = 0, scale = self.rich_poor_std)))) buyer = Buyer("buyer_poor_" + str(i), self, income = income, market_reach = self.poor_market_reach, type = cons.AGENT_TYPES.POOR) self.schedule.add(buyer) #Gets an available position index = indices[i] #Adds the buyer self.grid.place_agent(buyer, index) self.buyers.add(buyer) def get_distribution(self, name): """ Gets the corresponding function depending on the distribution """ if("CONSTANT" in str(name).upper()): name = name.replace(" ","") values = name.split("=") if(len(values) != 2): raise ValueError("If function is constant, should specify its value") constant = float(values[1]) return(lambda x: constant ) if(str(name).upper() == "UNIFORM"): return(lambda x: np.random.uniform()) if(str(name).upper() == "RASTER_AMENITIES"): return(CityGenerator.amenities_from_raster(self.grid_shape)) raise ValueError("No implementation for the distribution: " + str(name)) def get_tract_info(self, tract = 4): matrix = self.get_sold_type_matrix() array = get_tract_structure(matrix, tract) n = len(array) r = np.apply_along_axis(lambda x: np.sum(x == cons.AGENT_TYPES.RICH), 0, array) R = np.sum(matrix == cons.AGENT_TYPES.RICH) p = np.apply_along_axis(lambda x: np.sum(x == cons.AGENT_TYPES.POOR), 0, array) P = np.sum(matrix == cons.AGENT_TYPES.POOR) return(n,r,R,p,P) def get_sold_type_matrix(self): #Extract the matrix with the values matrix = np.array([[ self.patches[i,j].sold_type for j in range(self.patches.shape[1])] for i in range(self.patches.shape[0])]) return(matrix)