Skip to content

Commit

Permalink
filter invalid aoi gates in map_merger output
Browse files Browse the repository at this point in the history
  • Loading branch information
chenchenplus committed Jul 5, 2024
1 parent b5e8344 commit 369f64c
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 38 deletions.
6 changes: 6 additions & 0 deletions examples/merge_map.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import logging

from mosstool.type import Map
from mosstool.util.map_merger import merge_map

logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s",
)
maps = []
for i in [0, 1]:
with open(f"data/temp/test_{i}.pb", "rb") as f:
Expand Down
6 changes: 6 additions & 0 deletions examples/split_map.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import logging

import geojson

from mosstool.type import Map
from mosstool.util.map_splitter import split_map

logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(message)s",
)
with open("data/geojson/split_box.geojson", "r") as f:
bbox = geojson.load(f)
with open("data/map/m.pb", "rb") as f:
Expand Down
21 changes: 16 additions & 5 deletions mosstool/map/builder/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,13 @@ def __init__(
logging.info("Reading from pb files")
self.net = net
self.from_pb = True
pb_lane_uids = set()
# map_lanes & lane2data
for l in net.lanes:
line = LineString([[n.x, n.y, n.z] for n in l.center_line.nodes])
l_id = l.id
self.map_lanes[l_id] = line
pb_lane_uids.add(l_id)
self.lane2data[line] = {
"uid": l_id,
"in": [
Expand All @@ -225,7 +227,9 @@ def __init__(
"turn": l.turn,
"width": l.width,
}
self.lane_uid = max(pb_lane_uids) + 1
# map_roads
pb_road_uids = set()
for r in net.roads:
road_lanes = [self.map_lanes[l_id] for l_id in r.lane_ids]
drive_lanes = [
Expand All @@ -242,7 +246,9 @@ def __init__(
for l in road_lanes
if self.lane2data[l]["type"] == mapv2.LANE_TYPE_WALKING
]
self.map_roads[r.id] = {
r_id = r.id
pb_road_uids.add(r_id)
self.map_roads[r_id] = {
"lanes": drive_lanes,
"left_sidewalk": [
l
Expand All @@ -256,9 +262,11 @@ def __init__(
],
"highway": "",
"name": r.name,
"uid": r.id,
"uid": r_id,
}
self.road_uid = max(pb_road_uids) + 1
# map_junctions
pb_junc_uids = set()
for j in net.junctions:
junc_lanes = [self.map_lanes[l_id] for l_id in j.lane_ids]
all_junc_lane_coords = []
Expand All @@ -270,15 +278,18 @@ def __init__(
else:
x_center, y_center = np.mean(all_junc_lane_coords, axis=0)
z_center = 0
self.map_junctions[j.id] = {
j_id = j.id
pb_junc_uids.add(j_id)
self.map_junctions[j_id] = {
"lanes": junc_lanes,
"uid": j.id,
"uid": j_id,
"center": {
"x": x_center,
"y": y_center,
"z": z_center,
},
}
self.junc_uid = max(pb_junc_uids) + 1
# bbox
self.max_lon, self.max_lat = self.projector(
net.header.east, net.header.north, inverse=True
Expand Down Expand Up @@ -3808,7 +3819,7 @@ def create_subway_connections(geos: list, stas: list) -> List[List[int]]:
line, line.length / 3, line.length - line.length / 3
)
lane = cast(LineString, lane)
lane = offset_lane(lane, -0.5 * lane_width)
lane = offset_lane(lane, -0.495 * lane_width)
# Public section routes will not be added to lanes repeatedly.
if lane in self.lane2data:
station_connection_road_ids.append(
Expand Down
57 changes: 25 additions & 32 deletions mosstool/map/public_transport/public_transport_post.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import numpy as np
from pycityproto.city.routing.v2.routing_service_pb2 import GetRouteRequest
import pycityproto.city.map.v2.map_pb2 as mapv2

from tqdm import tqdm

from mosstool.trip.route import RoutingClient
Expand All @@ -15,12 +17,8 @@
__all__ = [
"public_transport_process",
]
# TODO: update pycityproto
T_SUBLINE_TYPE_UNSPECIFIED = 0
T_SUBLINE_TYPE_BUS = 1
T_SUBLINE_TYPE_SUBWAY = 2
T_ETA_FACTOR = 5
T_TAZ_LENGTH = 1500
ETA_FACTOR = 5
TAZ_LENGTH = 1500


async def _fill_public_lines(m: dict, server_address: str):
Expand All @@ -37,11 +35,11 @@ async def _fill_public_lines(m: dict, server_address: str):

def get_subline_type(pub_type: str):
if pub_type == "SUBWAY":
return T_SUBLINE_TYPE_SUBWAY
return mapv2.SUBLINE_TYPE_SUBWAY
elif pub_type == "BUS":
return T_SUBLINE_TYPE_BUS
return mapv2.SUBLINE_TYPE_BUS
else:
return T_SUBLINE_TYPE_UNSPECIFIED
return mapv2.SUBLINE_TYPE_UNSPECIFIED

def get_aoi_dis(aoi_id1, aoi_id2):
x1, y1 = aoi_center_point[aoi_id1]
Expand Down Expand Up @@ -132,7 +130,7 @@ def route_length(
"route_end": route_end,
"road_ids": road_ids,
"route_length": route_len,
"eta": eta * T_ETA_FACTOR,
"eta": eta * ETA_FACTOR,
}
)
if len(loop_res) > 0:
Expand Down Expand Up @@ -265,7 +263,7 @@ def _get_taz_cost_unit(arg):
station_durations = [aoi["external"]["duration"] for _, aoi in station_aois.items()]
subline_id = subline["id"]
subline_type = subline["type"]
if subline_type == T_SUBLINE_TYPE_SUBWAY:
if subline_type == mapv2.SUBLINE_TYPE_SUBWAY:
vehicle_speed = DEFAULT_MAX_SPEED["SUBWAY"]
else:
vehicle_speed = DEFAULT_MAX_SPEED["BUS"]
Expand Down Expand Up @@ -295,32 +293,32 @@ def get_taz_id(x, y):
drive_eta_time = total_drive_length / vehicle_speed + sum(
station_durations[i : i + i_offset]
)
key = (taz_id[0],taz_id[1],cur_aoi_ids[0])
key = (taz_id[0], taz_id[1], cur_aoi_ids[0])
min_tazs[key].append(drive_eta_time)
for (taz_x_id,taz_y_id,cur_aoi_id),etas in min_tazs.items():
for (taz_x_id, taz_y_id, cur_aoi_id), etas in min_tazs.items():
taz_costs.append(
{
"taz_x_id": taz_x_id,
"taz_y_id": taz_y_id,
"aoi_id": cur_aoi_id,
"cost": np.mean(etas),
}
)
{
"taz_x_id": taz_x_id,
"taz_y_id": taz_y_id,
"aoi_id": cur_aoi_id,
"cost": np.mean(etas),
}
)
return (subline_id, taz_costs)


def _post_compute(m: dict):
def _post_compute(m: dict, workers: int):
header = m["header"]
aois = {a["id"]: a for a in m["aois"]}
lanes = {l["id"]: l for l in m["lanes"]}
roads = {r["id"]: r for r in m["roads"]}
x_max, x_min = header["east"], header["west"]
y_max, y_min = header["north"], header["south"]
_, x_step = np.linspace(
x_min, x_max, max(int((x_max - x_min) / T_TAZ_LENGTH), 2), retstep=True
x_min, x_max, max(int((x_max - x_min) / TAZ_LENGTH), 2), retstep=True
)
_, y_step = np.linspace(
y_min, y_max, max(int((y_max - y_min) / T_TAZ_LENGTH), 2), retstep=True
y_min, y_max, max(int((y_max - y_min) / TAZ_LENGTH), 2), retstep=True
)
# update header
header["taz_x_step"] = x_step
Expand Down Expand Up @@ -364,35 +362,30 @@ def station_distance(road_ids, s_start: float, s_end: float) -> float:
route_lengths.append(station_distance(road_ids, s_start, s_end))
arg = (subline, station_aois, (x_min, x_step, y_min, y_step), route_lengths)
taz_cost_args.append(arg)
workers = cpu_count()
import time
start_time = time.time()
print(time.time())

with Pool(processes=workers) as pool:
taz_results = pool.map(
_get_taz_cost_unit,
taz_cost_args,
chunksize=max((len(taz_cost_args) // workers), 500),
)
print(time.time() - start_time)
subline_id2taz_costs = {r[0]: r[1] for r in taz_results}
for subline in sublines_data:
subline_id = subline["id"]
subline["taz_costs"] = subline_id2taz_costs[subline_id]
for sl in sublines_data:
if not sl["type"]==T_SUBLINE_TYPE_SUBWAY:
if not sl["type"] == mapv2.SUBLINE_TYPE_SUBWAY:
continue
transfer_stations = []
for aid in sl["aoi_ids"]:
station = aois[aid]
if len(station["subline_ids"])>1:
if len(station["subline_ids"]) > 1:
transfer_stations.append(station)

return m


def public_transport_process(m: dict, server_address: str):
def public_transport_process(m: dict, server_address: str, workers: int = cpu_count()):
m = asyncio.run(_fill_public_lines(m, server_address))
m = _post_compute(m)
m = _post_compute(m, workers)
return m
48 changes: 48 additions & 0 deletions mosstool/util/map_merger.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,61 @@
merge all input maps into one map
"""

import logging
import time
from copy import deepcopy
from typing import List, Optional

from ..map._map_util.format_checker import output_format_check
from ..type import Map
from .format_converter import dict2pb, pb2dict


def _filter_map(map_dict: dict):
"""
Filter invalid values in output map
"""
output_map = deepcopy(map_dict)
lanes = output_map["lanes"]
roads = output_map["roads"]
juncs = output_map["junctions"]
aois = output_map["aois"]
all_lane_ids = set(l["id"] for l in lanes)
# aoi
filter_aois = []
for aoi in aois:
aoi_id = aoi["id"]
aoi_pos_gate_key_tuples = (
("driving_positions", "driving_gates", "Driving"),
("walking_positions", "walking_gates", "Walking"),
)
for pos_key, gate_key, pos_type in aoi_pos_gate_key_tuples:
a_pos = aoi[pos_key]
a_gate = aoi[gate_key]
assert len(a_pos) == len(
a_gate
), f"Different {pos_type} position and gates length in Aoi {aoi_id}"
pos_idxes = []
for i, pos in enumerate(a_pos):
pos_l_id = pos["lane_id"]
if pos_l_id in all_lane_ids:
pos_idxes.append(i)
else:
logging.warning(
f"{pos_type} position in Aoi {aoi_id} has lane {pos_l_id} not in map!"
)
aoi[pos_key] = [pos for i, pos in enumerate(a_pos) if i in pos_idxes]
aoi[gate_key] = [gate for i, gate in enumerate(a_gate) if i in pos_idxes]
if all(len(aoi[pos_key]) == 0 for pos_key, _, _ in aoi_pos_gate_key_tuples):
# not connected to roadnet
logging.warning(f"Aoi {aoi_id} has no gates connected to the roadnet!")
continue
else:
filter_aois.append(aoi)
output_map["aois"] = filter_aois
return output_map


def merge_map(
partial_maps: List[Map],
output_path: Optional[str] = None,
Expand Down Expand Up @@ -68,6 +115,7 @@ def merge_map(
"east": max(x),
"projection": list(projstr_set)[0],
}
output_map_dict = _filter_map(output_map_dict)
output_format_check(output_map_dict, output_lane_length_check)
map_pb = dict2pb(output_map_dict, Map())
if output_path is not None:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "mosstool"
version = "0.2.18"
version = "0.2.19"
description = "MObility Simulation System toolbox "
authors = ["Jun Zhang <[email protected]>"]
license = "MIT"
Expand Down

0 comments on commit 369f64c

Please sign in to comment.