def test_finds_routes_between_created_OD_on_same_street( log, graph_handler: GraphHandler, routing_conf): # /paths/walk/quiet/60.214233,24.971411/60.213558,24.970785 od_settings = routing.parse_od_settings(TravelMode.WALK, RoutingMode.GREEN, routing_conf, orig_lat='60.214233', orig_lon='24.971411', dest_lat='60.213558', dest_lon='24.970785', aqi_updater=None) ecount = graph_handler.graph.ecount() assert ecount == 16643 od_nodes = routing.find_or_create_od_nodes(log, graph_handler, od_settings) path_set = routing.find_least_cost_paths(log, graph_handler, routing_conf, od_settings, od_nodes) path_FC, edge_FC = routing.process_paths_to_FC(log, graph_handler, routing_conf, od_settings, path_set) assert path_FC['type'] == 'FeatureCollection' assert edge_FC['type'] == 'FeatureCollection' assert ecount + 4 == graph_handler.graph.ecount() routing.delete_added_graph_features(graph_handler, od_nodes) graph_handler.reset_edge_cache()
def test_finds_routes_between_created_OD(log, graph_handler: GraphHandler, routing_conf, ensure_path_fc, ensure_edge_fc): # paths/walk/green/60.21352729760156,24.97086446863051/60.21128945130093,24.968455167858025 od_settings = routing.parse_od_settings(TravelMode.WALK, RoutingMode.GREEN, routing_conf, orig_lat='60.21352729760156', orig_lon='24.97086446863051', dest_lat='60.21128945130093', dest_lon='24.968455167858025', aqi_updater=None) ecount = graph_handler.graph.ecount() assert ecount == 16643 od_nodes = routing.find_or_create_od_nodes(log, graph_handler, od_settings) path_set = routing.find_least_cost_paths(log, graph_handler, routing_conf, od_settings, od_nodes) path_FC, edge_FC = routing.process_paths_to_FC(log, graph_handler, routing_conf, od_settings, path_set) ensure_path_fc(path_FC) ensure_edge_fc(edge_FC) assert ecount + 4 == graph_handler.graph.ecount() routing.delete_added_graph_features(graph_handler, od_nodes) graph_handler.reset_edge_cache()
def test_path_props_when_routing_with_created_OD_on_same_street( log, graph_handler: GraphHandler, routing_conf): # /paths/walk/quiet/60.214233,24.971411/60.213558,24.970785 od_settings = routing.parse_od_settings(TravelMode.WALK, RoutingMode.GREEN, routing_conf, orig_lat='60.214233', orig_lon='24.971411', dest_lat='60.213558', dest_lon='24.970785', aqi_updater=None) od_nodes = routing.find_or_create_od_nodes(log, graph_handler, od_settings) path_set = routing.find_least_cost_paths(log, graph_handler, routing_conf, od_settings, od_nodes) path_FC, edge_FC = routing.process_paths_to_FC(log, graph_handler, routing_conf, od_settings, path_set) routing.delete_added_graph_features(graph_handler, od_nodes) graph_handler.reset_edge_cache() path_1 = path_FC['features'][0] props = path_1['properties'] assert props['length'] == 82.8 assert round(sum(props['noises'].values()), 1) == round(props['length'], 1) assert round(sum(props['gvi_cl_exps'].values()), 1) == round(props['length'], 1) assert round(sum(props['gvi_cl_pcts'].values()), 1) == 100.0 # assert round(sum(props['aqi_cl_exps'].values()),1) == round(props['length'],1) # assert round(sum(props['aqi_cl_pcts'].values()),1) == 100.0 assert round(sum(props['noise_range_exps'].values()), 1) == round(props['length'], 1) assert round(sum(props['noise_pcts'].values()), 1) == 100.0 assert props['bike_time_cost'] == 82.8 assert props['bike_safety_cost'] == 82.8
def test_creates_also_dest_node_if_origin_was_created( log, graph_handler: GraphHandler, routing_conf): # paths/walk/green/60.213859473184016,24.971143562116595/60.21210611561355,24.969360716643195 od_settings = routing.parse_od_settings(TravelMode.WALK, RoutingMode.GREEN, routing_conf, orig_lat='60.213859473184016', orig_lon='24.971143562116595', dest_lat='60.21210611561355', dest_lon='24.969360716643195', aqi_updater=None) ecount = graph_handler.graph.ecount() assert ecount == 16643 od_nodes = routing.find_or_create_od_nodes(log, graph_handler, od_settings) path_set = routing.find_least_cost_paths(log, graph_handler, routing_conf, od_settings, od_nodes) path_FC, edge_FC = routing.process_paths_to_FC(log, graph_handler, routing_conf, od_settings, path_set) assert path_FC['type'] == 'FeatureCollection' assert edge_FC['type'] == 'FeatureCollection' assert ecount + 4 == graph_handler.graph.ecount( ) # if origin was already created, then also dest is created routing.delete_added_graph_features(graph_handler, od_nodes) graph_handler.reset_edge_cache()
def test_finds_routes_between_existing_O_and_created_D_on_same_street( log, graph_handler: GraphHandler, routing_conf): # /paths/walk/green/60.212149138928254,24.969463681172613/60.213886742565194,24.971240777950726 od_settings = routing.parse_od_settings(TravelMode.WALK, RoutingMode.GREEN, routing_conf, orig_lat='60.212149138928254', orig_lon='24.969463681172613', dest_lat='60.213886742565194', dest_lon='24.971240777950726', aqi_updater=None) ecount = graph_handler.graph.ecount() assert ecount == 16643 od_nodes = routing.find_or_create_od_nodes(log, graph_handler, od_settings) path_set = routing.find_least_cost_paths(log, graph_handler, routing_conf, od_settings, od_nodes) path_FC, edge_FC = routing.process_paths_to_FC(log, graph_handler, routing_conf, od_settings, path_set) assert path_FC['type'] == 'FeatureCollection' assert edge_FC['type'] == 'FeatureCollection' assert ecount + 2 == graph_handler.graph.ecount() routing.delete_added_graph_features(graph_handler, od_nodes) graph_handler.reset_edge_cache()
def delete_added_graph_features(G: GraphHandler, od_nodes: OdData): """Keeps the graph clean by removing new nodes & edges created during routing from the graph. """ delete_o_node = ( od_nodes.orig_node.id, ) if od_nodes.orig_link_edges else () delete_d_node = ( od_nodes.dest_node.id, ) if od_nodes.dest_link_edges else () G.drop_nodes_edges(delete_o_node + delete_d_node)
def __find_safest_path(G: GraphHandler, od_nodes: OdData) -> Path: return Path(path_id=PathType.SAFEST.value, path_type=PathType.SAFEST, edge_ids=G.get_least_cost_path( od_nodes.orig_node.id, od_nodes.dest_node.id, weight=E.bike_safety_cost.value))
def test_removes_linking_edges_after_routing(log, graph_handler: GraphHandler, routing_conf): # paths/walk/green/60.21352729760156,24.97086446863051/60.21128945130093,24.968455167858025 od_settings = routing.parse_od_settings(TravelMode.WALK.value, RoutingMode.GREEN.value, routing_conf, orig_lat='60.21352729760156', orig_lon='24.97086446863051', dest_lat='60.21128945130093', dest_lon='24.968455167858025', aqi_updater=None) ecount = graph_handler.graph.ecount() od_nodes = routing.find_or_create_od_nodes(log, graph_handler, od_settings) assert ecount + 4 == graph_handler.graph.ecount() routing.delete_added_graph_features(graph_handler, od_nodes) graph_handler.reset_edge_cache() assert ecount == graph_handler.graph.ecount()
def __find_fastest_path(G: GraphHandler, od_nodes: OdData, fastest_path_cost_attr: E) -> Path: return Path(path_id=PathType.FASTEST.value, path_type=PathType.FASTEST, edge_ids=G.get_least_cost_path( od_nodes.orig_node.id, od_nodes.dest_node.id, weight=fastest_path_cost_attr.value))
def get_orig_dest_nodes_and_linking_edges(G: GraphHandler, orig_point: Point, dest_point: Point) -> OdData: """Selects nearest nodes ad OD if they are "near enough", otherwise creates new nodes either on the nearest existing edges or on the previously created links (i.e. temporary) edges. """ orig_link_edges = () dest_link_edges = () long_distance: bool = orig_point.distance(dest_point) > 5000 try: orig_node = get_nearest_node(G, orig_point, avoid_node_creation=True, long_distance=long_distance) except Exception: raise RoutingException(ErrorKey.ORIGIN_NOT_FOUND.value) # add linking edges to graph if new node was created (on the nearest edge) if orig_node.link_to_edge_spec: orig_link_edges = get_link_edge_data(orig_node.id, orig_node.link_to_edge_spec, create_inbound_links=False, create_outbound_links=True) try: dest_node = get_nearest_node(G, dest_point, avoid_node_creation=not orig_link_edges, temp_link_edges=orig_link_edges, long_distance=long_distance) except Exception: raise RoutingException(ErrorKey.DESTINATION_NOT_FOUND.value) # add linking edges to graph if new node was created (on the nearest edge) if dest_node.link_to_edge_spec: dest_link_edges = get_link_edge_data( dest_node.id, dest_node.link_to_edge_spec, create_inbound_links=True, create_outbound_links=False, ) G.add_new_edges_to_graph(orig_link_edges + dest_link_edges) return OdData(orig_node, dest_node, orig_link_edges, dest_link_edges)
def __find_exp_optimized_paths(G: GraphHandler, od_settings: OdSettings, od_nodes: OdData): cost_prefix = cost_prefix_dict[od_settings.travel_mode][ od_settings.routing_mode] return [ Path(path_id=f'{cost_prefix}{sen}', path_type=path_type_by_routing_mode[od_settings.routing_mode], edge_ids=G.get_least_cost_path(od_nodes.orig_node.id, od_nodes.dest_node.id, weight=f'{cost_prefix}{sen}'), cost_coeff=sen) for sen in od_settings.sensitivities ]
def get_nearest_node(G: GraphHandler, point: Point, avoid_node_creation: bool, temp_link_edges: Tuple[dict] = (), long_distance: bool = False) -> OdNodeData: nearest_edge = G.find_nearest_edge(point) if not nearest_edge: raise Exception('Nearest edge not found') nearest_node: int = G.find_nearest_node(point) if not nearest_node: raise Exception('Nearest node not found') nearest_node_geom = G.get_node_point_geom(nearest_node) nearest_edge_point = __get_closest_point_on_line( nearest_edge.attrs[E.geometry.value], point) nearest_node_dist = nearest_node_geom.distance(point) od_as_nearest_node = __maybe_use_nearest_existing_node( avoid_node_creation, long_distance, nearest_node, nearest_node_dist, nearest_edge) if od_as_nearest_node: return od_as_nearest_node # still here, thus creating a new node to graph and linking edges for it nearest_edge = __select_nearest_edge(nearest_edge_point, nearest_edge, temp_link_edges) # create a new node on the nearest edge to the graph new_node = G.add_new_node_to_graph(nearest_edge_point) # new edges from the new node to existing nodes need to be created to the graph # hence return the geometry of the nearest edge and the nearest point on the nearest edge return OdNodeData(id=new_node, is_temp_node=True, link_to_edge_spec=LinkToEdgeSpec( edge=nearest_edge.attrs, snap_point=nearest_edge_point))
def test_path_props_when_routing_with_created_OD(log, graph_handler: GraphHandler, routing_conf): # paths/walk/green/60.21352729760156,24.97086446863051/60.21128945130093,24.968455167858025 od_settings = routing.parse_od_settings(TravelMode.WALK, RoutingMode.GREEN, routing_conf, orig_lat='60.21352729760156', orig_lon='24.97086446863051', dest_lat='60.21128945130093', dest_lon='24.968455167858025', aqi_updater=None) od_nodes = routing.find_or_create_od_nodes(log, graph_handler, od_settings) path_set = routing.find_least_cost_paths(log, graph_handler, routing_conf, od_settings, od_nodes) path_FC, edge_FC = routing.process_paths_to_FC(log, graph_handler, routing_conf, od_settings, path_set) routing.delete_added_graph_features(graph_handler, od_nodes) graph_handler.reset_edge_cache() path_1 = path_FC['features'][0] props = path_1['properties'] assert props['length'] == 291.97 assert round(sum(props['noises'].values()), 1) == round(props['length'], 1) assert round(sum(props['gvi_cl_exps'].values()), 1) == round(props['length'], 1) assert round(sum(props['gvi_cl_pcts'].values()), 1) == 100.0 # assert round(sum(props['aqi_cl_exps'].values()),1) == round(props['length'],1) # assert round(sum(props['aqi_cl_pcts'].values()),1) == 100.0 assert round(sum(props['noise_range_exps'].values()), 1) == round(props['length'], 1) assert round(sum(props['noise_pcts'].values()), 1) == 100.0 assert props['bike_time_cost'] == 291.93 assert props['bike_safety_cost'] == 291.93
def test_path_props_when_routing_with_created_D(log, graph_handler: GraphHandler, routing_conf): # origin is existing node, destination is new # paths/walk/quiet/60.212103883291405,24.969382893894505/60.21390217111113,24.971206858808813 od_settings = routing.parse_od_settings(TravelMode.WALK, RoutingMode.GREEN, routing_conf, orig_lat='60.212103883291405', orig_lon='24.969382893894505', dest_lat='60.21390217111113', dest_lon='24.971206858808813', aqi_updater=None) od_nodes = routing.find_or_create_od_nodes(log, graph_handler, od_settings) path_set = routing.find_least_cost_paths(log, graph_handler, routing_conf, od_settings, od_nodes) path_FC, edge_FC = routing.process_paths_to_FC(log, graph_handler, routing_conf, od_settings, path_set) routing.delete_added_graph_features(graph_handler, od_nodes) graph_handler.reset_edge_cache() path_1 = path_FC['features'][0] props = path_1['properties'] assert props['length'] == 218.58 assert round(sum(props['noises'].values()), 1) == round(props['length'], 1) assert round(sum(props['gvi_cl_exps'].values()), 1) == round(props['length'], 1) assert round(sum(props['gvi_cl_pcts'].values()), 1) == 100.0 # assert round(sum(props['aqi_cl_exps'].values()),1) == round(props['length'],1) # assert round(sum(props['aqi_cl_pcts'].values()),1) == 100.0 assert round(sum(props['noise_range_exps'].values()), 1) == round(props['length'], 1) assert round(sum(props['noise_pcts'].values()), 1) == 100.0 assert props['bike_time_cost'] == 218.52 assert props['bike_safety_cost'] == 218.52
def set_path_edges(self, G: GraphHandler) -> None: """Iterates through the path's edge IDs and loads edge attributes from a graph. """ self.edges = G.get_path_edges_by_ids(self.edge_ids)
- Set graph_file to 'graphs/kumpula.graphml' in src/conf.py - Start Green Paths routing app to handle routing requests at localhost:5000 """ from gp_server.app.graph_handler import GraphHandler from gp_server.app.types import PathEdge from gp_server.app.logger import Logger import gp_server.app.noise_exposures as noise_exps from typing import List, Tuple, Union import requests import traceback # initialize graph handler for fetching edge data after routing G = GraphHandler(Logger(), 'graphs/kumpula.graphml') # define example ODs od_list = [ ((60.21743, 24.96996), (60.2123, 24.95978)), ((60.21743, 24.96996), (60.2118, 24.95952)), ((60.20151, 24.96206), (60.2102, 24.96887)), ((60.21495, 24.97971), (60.20166, 24.968)) ] def get_od_paths(od_coords: Tuple[Tuple[float, float]]) -> Union[dict, None]: """Returns paths from local Green Paths routing API. If routing fails, returns None. """ od_request_coords = f'{od_coords[0][0]},{od_coords[0][1]}/{od_coords[1][0]},{od_coords[1][1]}'
def graph_handler(log): patch_conf = patch('gp_server.conf.conf', test_conf) with patch_conf: yield GraphHandler(log, test_conf.graph_file, routing.get_routing_conf())
app = Flask(__name__) CORS(app) # set logging to use gunicorn logger & logging level if __name__ != '__main__': gunicorn_logger = logging.getLogger('gunicorn.error') app.logger.handlers = gunicorn_logger.handlers app.logger.setLevel(gunicorn_logger.level) log = Logger(app_logger=app.logger, b_printing=False) routing_conf = routing.get_routing_conf() # initialize graph G = GraphHandler(log, conf.graph_file, routing_conf) if conf.clean_paths_enabled: aqi_updater = GraphAqiUpdater(log, G, r'aqi_updates/', routing_conf) else: aqi_updater = None # start AQI map data service aqi_map_data_api = get_aqi_map_data_api(log, r'aqi_updates/') aqi_map_data_api.start() @app.route('/') def hello_world(): return 'Keep calm and walk green paths.'