diff --git a/evrouting/graph_tools.py b/evrouting/graph_tools.py index 1d457c6fb5db13cd024ea896f01ba5f6c5598d41..664c3716edddde2decdf52d2d26bca6e075ca42f 100644 --- a/evrouting/graph_tools.py +++ b/evrouting/graph_tools.py @@ -12,6 +12,7 @@ LABEL_KEY = 'label' CHARGING_COEFFICIENT_KEY = 'c' DISTANCE_KEY = 'weight' CONSUMPTION_KEY = 'c' +HAVERSINE_KEY = 'haversine' def node_convert(n: TemplateNode) -> NodeData: @@ -36,3 +37,7 @@ def charging_cofficient(G: nx.Graph, n: Node) -> ChargingCoefficient: def label(G: nx.Graph, u: Node) -> str: return G.nodes[u][LABEL_KEY] + + +def sum_weights(G, path, weight) -> float: + return sum(G[u][v][weight] for u, v in zip(path[:-1], path[1:])) diff --git a/evrouting/osm/imports.py b/evrouting/osm/imports.py index 84b7e29ca21af32ff940fd12b3020fc8cc8efc7d..3878db55451d826c0e182375328736edd910f17c 100644 --- a/evrouting/osm/imports.py +++ b/evrouting/osm/imports.py @@ -19,15 +19,13 @@ import itertools import networkx as nx import rtree -from evrouting.graph_tools import CHARGING_COEFFICIENT_KEY, DISTANCE_KEY +from evrouting.graph_tools import CHARGING_COEFFICIENT_KEY, DISTANCE_KEY, HAVERSINE_KEY from evrouting.osm.const import ms_to_kmh from evrouting.osm.profiles import speed from evrouting.osm.routing import point, haversine_distance logger = logging.getLogger(__name__) -HAVERSINE_KEY = 'haversine' - class OSMGraph(nx.DiGraph): """ diff --git a/evrouting/osm/routing.py b/evrouting/osm/routing.py index 0d9b110359fb39f20803c954087510505261505b..e752c39c16b6edacaa6a8d7e675bbffb39975349 100644 --- a/evrouting/osm/routing.py +++ b/evrouting/osm/routing.py @@ -3,6 +3,10 @@ from math import radians, cos, sin, asin, sqrt import networkx as nx +from evrouting.T import ConsumptionFunction, Result, EmptyResult +from evrouting.graph_tools import ( + DISTANCE_KEY, HAVERSINE_KEY, CONSUMPTION_KEY, sum_weights +) from evrouting.osm.const import ms_to_kmh lat = float @@ -30,7 +34,7 @@ def haversine_distance(lon1, lat1, lon2, lat2, unit_m=True): return c * r -def shortest_path(G, s: point, t: point, profile): +def shortest_path(G, s: point, t: point, profile) -> Result: """Calc A* shortest path.""" def dist(u, v): @@ -42,7 +46,15 @@ def shortest_path(G, s: point, t: point, profile): unit_m=True ) / profile['maxspeed'] * ms_to_kmh - return nx.astar_path(G, s, t, heuristic=dist) + try: + path = nx.astar_path(G, s, t, heuristic=dist) + except nx.NetworkXNoPath: + return EmptyResult() + + return Result( + trip_time=sum_weights(G, path, DISTANCE_KEY), + charge_path=[(n, 0) for n in path] + ) def to_coordinates(G, path): @@ -59,3 +71,19 @@ def to_coordinates(G, path): return lon, lat return list(map(get_coordinates, path)) + + +def consumption_function_factory(consumption: float) -> ConsumptionFunction: + """ + :param consumption: in kWh/km + :return: consi + """ + + def c(G, u, v): + """Returns consumption in Wh from u to v.""" + try: + return G[u][v][HAVERSINE_KEY] * consumption + except KeyError: + return G[u][v][CONSUMPTION_KEY] + + return c diff --git a/tests/osm/test_osm_charge.py b/tests/osm/test_osm_charge.py index f5b06efcc4bda4e2a1c14407032b42cc14f552ea..a5f410f6d856d5b271f91a35415e23aab1c9fe40 100644 --- a/tests/osm/test_osm_charge.py +++ b/tests/osm/test_osm_charge.py @@ -5,10 +5,12 @@ import pytest from evrouting import charge from evrouting.T import Result -from evrouting.osm.imports import read_osm, OSMGraph, HAVERSINE_KEY +from evrouting.osm.imports import read_osm, OSMGraph from evrouting.osm.profiles import car from evrouting.osm.routing import shortest_path -from evrouting.graph_tools import CHARGING_COEFFICIENT_KEY, DISTANCE_KEY, CONSUMPTION_KEY +from evrouting.graph_tools import ( + CHARGING_COEFFICIENT_KEY, DISTANCE_KEY, CONSUMPTION_KEY, HAVERSINE_KEY +) @pytest.fixture @@ -48,7 +50,7 @@ def test_insert_charging_stations_close(graph): graph.insert_charging_stations(S) - assert graph.nodes[0][CHARGING_COEFFICIENT_KEY] == 22.0 + assert graph.nodes[0][CHARGING_COEFFICIENT_KEY] == 22.0 / 3.6 assert CHARGING_COEFFICIENT_KEY not in graph.nodes[1] @@ -58,7 +60,7 @@ def test_insert_charging_stations_eq(graph): graph.insert_charging_stations(S) - assert graph.nodes[0][CHARGING_COEFFICIENT_KEY] == 22.0 + assert graph.nodes[0][CHARGING_COEFFICIENT_KEY] == 22.0 / 3.6 assert CHARGING_COEFFICIENT_KEY not in graph.nodes[1] @@ -77,8 +79,8 @@ def test_shortest_route(map_graph): "4955446051", "418009799" ] - - assert route == shortest_path(map_graph, _s, _t, car) + result = shortest_path(map_graph, _s, _t, car) + assert route == [n for n, t in result.charge_path] def test_shortest_route_dimensions(map_graph): @@ -87,8 +89,8 @@ def test_shortest_route_dimensions(map_graph): _s = map_graph.find_nearest(s) _t = map_graph.find_nearest(t) - path = shortest_path(map_graph, _s, _t, car) - + result = shortest_path(map_graph, _s, _t, car) + path = [n for n, t in result.charge_path] time = sum([map_graph[u][v][DISTANCE_KEY] for u, v in zip(path[:-1], path[1:])]) distance = sum([map_graph[u][v][HAVERSINE_KEY] for u, v in zip(path[:-1], path[1:])]) @@ -129,7 +131,7 @@ def test_charge_shortest_route_dimensions(map_graph): path = shortest_path(map_graph, _s, _t, car) assert type(result) is Result - assert [n for n, t in result.charge_path] == path + assert result.charge_path == path.charge_path def test_charge_shortest_route_stop(map_graph):