def __init__(self, params: dict): self.start_coords = GeoLocation.from_degrees( params['start']['center']['lat'], params['start']['center']['lng']) self.end_coords = GeoLocation.from_degrees( params['end']['center']['lat'], params['end']['center']['lng']) self.start_magnitude = params['start']['intensity'] self.end_magnitude = params['end']['intensity'] self.start_radius = params['start']['radius'] self.end_radius = params['end']['radius'] self.N_POINTS = 10
def construct_settlement_view_from_parts(self): print("Building settlement view from parts...") graph_settlement_view = nx.Graph() # first we'll read all the cities -- our RED nodes, and store them as nodes into the settlement_view settlement_df = pd.read_csv(f"{self.DATA_DIR}/cal.csv") settlement_df.sort_values(by='population', ascending=False, inplace=True) for index, city in settlement_df.iterrows(): graph_settlement_view.add_node(city['id'], pos=GeoLocation.from_degrees( float(city['lat']), float(city['lng'])), name=city['city'], population=city['population']) print(f"Read {graph_settlement_view.number_of_nodes()} red nodes.") # now let's read the parts parts = [ nx.read_gpickle( f"{self.DATA_DIR}/settlement_parts/graph_settlement_view_0.gpickle" ), nx.read_gpickle( f"{self.DATA_DIR}/settlement_parts/graph_settlement_view_1.gpickle" ), nx.read_gpickle( f"{self.DATA_DIR}/settlement_parts/graph_settlement_view_2.gpickle" ), nx.read_gpickle( f"{self.DATA_DIR}/settlement_parts/graph_settlement_view_3.gpickle" ), nx.read_gpickle( f"{self.DATA_DIR}/settlement_parts/graph_settlement_view_4.gpickle" ) ] for part in parts: for u, v, a in part.edges(data=True): # print(u, v, a) # import sys; sys.exit(); graph_settlement_view.add_edge(u, v, blue_nodes=a['blue_nodes']) print(f"{graph_settlement_view.number_of_nodes()} nodes and " f"{graph_settlement_view.number_of_edges()} edges.") nx.write_gpickle(graph_settlement_view, f"{self.DATA_DIR}/graph_settlement_view.gpickle") self.graph_settlement_view = graph_settlement_view
def construct_segment_view(self): print("Building segment view...") graph_segment_view = nx.Graph() with open(f"{self.DATA_DIR}/cal.cnode.csv") as f: for row in csv.reader(f): lat = float(row[2]) lng = float(row[1]) node_id = row[0] graph_segment_view.add_node(node_id, pos=GeoLocation.from_degrees( lat, lng), mappedToCity=False) with open(f"{self.DATA_DIR}/cal.cedge.csv") as f: for row in csv.reader(f): graph_segment_view.add_edge(row[1], row[2], d=row[3]) nx.write_gpickle(graph_segment_view, f"{self.DATA_DIR}/graph_segment_view.gpickle") self.graph_segment_view = graph_segment_view print("Done") print(graph_segment_view.number_of_nodes(), "blue segments.") print(graph_segment_view.number_of_edges(), "blue edges.")
def get_disaster_magnitudes_for_coordinates(self, coordinates): multi_magnitudes = [] lat_increment = (self.end_coords.deg_lat - self.start_coords.deg_lat) / self.N_POINTS long_increment = (self.end_coords.deg_lon - self.start_coords.deg_lon) / self.N_POINTS magnitude_increment = (self.end_magnitude - self.start_magnitude) / self.N_POINTS radius_increment = (self.end_radius - self.start_radius) / self.N_POINTS for i in range(self.N_POINTS + 1): center = GeoLocation.from_degrees( self.start_coords.deg_lat + i * lat_increment, self.start_coords.deg_lon + i * long_increment) magnitude = self.start_magnitude + i * magnitude_increment radius = self.start_radius + i * radius_increment distances = np.array( [center.distance_to(coordinate) for coordinate in coordinates]) multi_magnitudes.append(magnitude * np.exp(-np.multiply(distances, distances) / (2 * radius * radius))) # could instead use a bounded inverse linear function, i.e. min(radius/distance, 1) return np.max(np.array(multi_magnitudes), axis=0)
def construct_tile_view(self): print("Building tile view...") graph_segment_view = nx.read_gpickle( f"{self.DATA_DIR}/graph_segment_view.gpickle") graph_tile_view = nx.Graph() min_lat = 400 max_lat = -400 min_lng = 400 max_lng = -400 with open(f"{self.DATA_DIR}/cal.cnode.csv") as f: for row in csv.reader(f): lat = float(row[2]) lng = float(row[1]) min_lat = min(lat, min_lat) max_lat = max(lat, max_lat) min_lng = min(lng, min_lng) max_lng = max(lng, max_lng) print( f"min_lat: {min_lat} \tmax_lat: {max_lat} \tmin_lng: {min_lng} \tmax_lng: {max_lng} \t" ) delta = 0.01 # just some small utility functions def get_tile_id(_lat, _lng): return (math.floor( (_lat - min_lat) / delta), math.floor( (_lng - min_lng) / delta)) max_tile_i, max_tile_j = get_tile_id(max_lat, max_lng) for i in range(max_tile_i + 1): for j in range(max_tile_j + 1): sw_loc = GeoLocation.from_degrees(min_lat + i * delta, min_lng + j * delta) ne_loc = GeoLocation.from_degrees(min_lat + (i + 1) * delta, min_lng + (j + 1) * delta) center_loc = GeoLocation.from_degrees(min_lat + i * delta / 2, min_lng + j * delta / 2) graph_tile_view.add_node((i, j), sw_loc=sw_loc, ne_loc=ne_loc, center_loc=center_loc, segment_nodes=set(), segment_edges=set()) # now we assign blue nodes to tiles they belong to blue_nodes = graph_segment_view.nodes(data=True) for node, attr in blue_nodes: location = attr['pos'] tile_id = get_tile_id(location.deg_lat, location.deg_lon) graph_tile_view.nodes[tile_id]['segment_nodes'].append(node) # now we assign blue edges to tiles # we should ideally take all the tiles along the line joining u to v, then add a segment edge to all those # tiles. But no big deal for u, v in graph_segment_view.edges(): location = blue_nodes[u]['pos'] tile1 = get_tile_id(location.deg_lat, location.deg_lon) location = blue_nodes[v]['pos'] tile2 = get_tile_id(location.deg_lat, location.deg_lon) graph_tile_view.nodes[tile1]['segment_edges'].append((u, v)) if tile1 != tile2: graph_tile_view.nodes[tile2]['segment_edges'].append((u, v)) # we need to delete those tiles that don't contain any roads at all. Would greatly speed up computation node_indices = [] segment_lengths = [] for node, attr in graph_tile_view.nodes(data=True): node_indices.append(node) segment_lengths.append(len(attr['segment_nodes'])) for node, length in zip(node_indices, segment_lengths): if length == 0: graph_tile_view.remove_node(node) nx.write_gpickle(graph_tile_view, f"{self.DATA_DIR}/graph_tile_view.gpickle") self.graph_tile_view = graph_tile_view print(f"Done! Created {graph_tile_view.number_of_nodes()} tiles.")
def construct_settlement_view_using_combined_nodes(self): print("Building settlement view...") graph_settlement_view = nx.Graph() # first we'll read all the cities -- our RED nodes, and store them as nodes into the settlement_view settlement_df = pd.read_csv(f"{self.DATA_DIR}/cal.csv") settlement_df.sort_values(by='population', ascending=False, inplace=True) for index, city in settlement_df.iterrows(): graph_settlement_view.add_node(city['id'], pos=GeoLocation.from_degrees( float(city['lat']), float(city['lng'])), name=city['city'], population=city['population']) print(f"Read {graph_settlement_view.number_of_nodes()} red nodes.") # now, we'll combine all blue nodes within city perimeters into a single node graph_segment_view_nodes_combined = self.get_combined_nodes_within_city_perimeter( True) print( f"Read {graph_segment_view_nodes_combined.number_of_nodes()} merged blue nodes." ) # we'll also combine all blue nodes which have just two neighbors graph_segment_two_neighbor_combined_nodes = self.get_two_neighbor_combined_nodes( True) print( f"Read {graph_segment_two_neighbor_combined_nodes.number_of_nodes()} merged blue nodes." ) # we'll do the same again graph_segment_four_neighbor_combined_nodes = self.get_four_neighbor_combined_nodes( True) print( f"Read {graph_segment_four_neighbor_combined_nodes.number_of_nodes()} merged blue nodes." ) # for every red node u, # for every red node v: # remove all red nodes other than u and v # find shortest blue path between u and v # add red edge between u and v all_red_nodes = list(graph_settlement_view.nodes()) import time start = time.time() print(f"Start: {start}") red_node_degrees = dict() red_nodes_with_edges = list() for red_node in all_red_nodes: red_node_degrees[ red_node] = graph_segment_four_neighbor_combined_nodes.degree( red_node) if red_node_degrees[red_node]: red_nodes_with_edges.append(red_node) # for u, v in combinations(all_red_nodes, 2): for i, u in enumerate(red_nodes_with_edges): for j, v in enumerate(red_nodes_with_edges[i + 1:]): print(f"\r{i}x{j} / {len(red_nodes_with_edges)}", end="") graph_segment_view_other_nodes_removed = graph_segment_four_neighbor_combined_nodes.copy( ) for red_node in red_nodes_with_edges: if red_node not in [u, v]: graph_segment_view_other_nodes_removed.remove_node( red_node) if nx.has_path(graph_segment_view_other_nodes_removed, u, v): path = nx.shortest_path( graph_segment_view_other_nodes_removed, u, v) graph_settlement_view.add_edge(u, v, blue_nodes=path) print(f"\tDuration: {time.time() - start}", end="") nx.write_gpickle(graph_settlement_view, f"{self.DATA_DIR}/graph_settlement_view.gpickle") self.graph_settlement_view = graph_settlement_view
def get_combined_nodes_within_city_perimeter(self, read_from_file=False): if read_from_file: return nx.read_gpickle( f"{self.DATA_DIR}/graph_segment_view_nodes_combined.gpickle") settlement_df = pd.read_csv(f"{self.DATA_DIR}/cal.csv") # sort by population -> larger cities will get to pick the blue nodes first. settlement_df.sort_values(by='population', ascending=False, inplace=True) graph_segment_view = nx.read_gpickle( f"{self.DATA_DIR}/graph_segment_view.gpickle") graph_segment_view_nodes_combined = graph_segment_view.copy() # let's start print("Merging blue nodes...") print( f"Started with {graph_segment_view_nodes_combined.number_of_nodes()} blue segments." ) counter, num_cities = 0, len( settlement_df) # just so we can keep tabs in the console for index, city in settlement_df.iterrows(): counter += 1 print( f"\r{counter}/{num_cities} :: {city['city']} ", end="") city_location = GeoLocation.from_degrees(float(city['lat']), float(city['lng'])) sw_bound, ne_bound = city_location.bounding_locations( self.CITY_PERIMETER) # first we'll add a blue node that will represent the entire city graph_segment_view_nodes_combined.add_node( city['id'], pos=GeoLocation.from_degrees(float(city['lat']), float(city['lng'])), mappedToCity=True) representative_node = city['id'] # now we will combine all blue nodes that fall within the city perimeters for node_id, blue_node in graph_segment_view_nodes_combined.nodes( data=True): try: if blue_node['mappedToCity']: continue except KeyError: pass # try: if blue_node['pos'].within_bounds(sw_bound, ne_bound): graph_segment_view_nodes_combined = nx.contracted_nodes( graph_segment_view_nodes_combined, representative_node, str(node_id), self_loops=False) # when we merge nodes, it stores all the properties of the previous node too. # this can get very long. and we don't need it anyway. therefore we clear this field. graph_segment_view_nodes_combined.nodes[ representative_node]['contraction'] = {} # except: # print(blue_node) # we're done! let's finally write the graph into a file nx.write_gpickle( graph_segment_view_nodes_combined, f"{self.DATA_DIR}/graph_segment_view_nodes_combined.gpickle") print( f"\nAfter merging we have {graph_segment_view_nodes_combined.number_of_nodes()} blue segments." ) return graph_segment_view_nodes_combined
def __init__(self, params: dict): self.epicenter_coords = GeoLocation.from_degrees( params['center']['lat'], params['center']['lng']) self.magnitude = params['intensity'] self.sigma_radius = params['radius']