From 03d04804130697f3f9217af4ba93cc1beb4ace11 Mon Sep 17 00:00:00 2001 From: yanjunbo <13008250033@163.com> Date: Fri, 27 Sep 2024 17:42:59 +0800 Subject: [PATCH] migrate `person.v1` to `person.v2` --- examples/random_persons.py | 7 +- .../map/_map_util/aois/append_aois_matcher.py | 31 +- mosstool/map/_map_util/const.py | 5 +- mosstool/map/builder/builder.py | 11 +- mosstool/trip/generator/__init__.py | 5 +- mosstool/trip/generator/_util/const.py | 30 +- mosstool/trip/generator/_util/utils.py | 299 ++++++++++++------ mosstool/trip/generator/generate_from_od.py | 24 +- mosstool/trip/generator/random.py | 25 +- mosstool/trip/generator/template.py | 63 +++- mosstool/trip/route/preroute.py | 19 +- mosstool/trip/sumo/route.py | 19 +- mosstool/type/__init__.py | 40 +-- pyproject.toml | 2 +- 14 files changed, 389 insertions(+), 191 deletions(-) diff --git a/examples/random_persons.py b/examples/random_persons.py index b41c110..5f4782a 100644 --- a/examples/random_persons.py +++ b/examples/random_persons.py @@ -1,6 +1,7 @@ -from mosstool.trip.generator import PositionMode, RandomGenerator, DEFAULT_PERSON +from mosstool.trip.generator import (V1_DEFAULT_PERSON, V2_DEFAULT_PERSON, + PositionMode, RandomGenerator) from mosstool.trip.route import RoutingClient, pre_route -from mosstool.type import Map, Persons, TripMode, Person +from mosstool.type import Map, TripMode, Person, Persons from mosstool.util.format_converter import pb2json @@ -10,7 +11,7 @@ async def main(): m.ParseFromString(f.read()) template = Person() - template.CopyFrom(DEFAULT_PERSON) + template.CopyFrom(V1_DEFAULT_PERSON) template.vehicle_attribute.model = "normal" template.pedestrian_attribute.model = "normal" rg = RandomGenerator( diff --git a/mosstool/map/_map_util/aois/append_aois_matcher.py b/mosstool/map/_map_util/aois/append_aois_matcher.py index f51f70e..48e634f 100644 --- a/mosstool/map/_map_util/aois/append_aois_matcher.py +++ b/mosstool/map/_map_util/aois/append_aois_matcher.py @@ -11,14 +11,25 @@ import shapely.ops as ops from scipy.spatial import KDTree from shapely.affinity import scale -from shapely.geometry import (LineString, MultiLineString, MultiPoint, - MultiPolygon, Point, Polygon) +from shapely.geometry import ( + LineString, + MultiLineString, + MultiPoint, + MultiPolygon, + Point, + Polygon, +) from shapely.strtree import STRtree from ....type import AoiType from ..._util.angle import abs_delta_angle, delta_angle -from ..._util.line import (connect_line_string, get_line_angle, - get_start_vector, line_extend, offset_lane) +from ..._util.line import ( + connect_line_string, + get_line_angle, + get_start_vector, + line_extend, + offset_lane, +) from .utils import geo_coords # ATTENTION: In order to achieve longer distance POI merging, the maximum recursion depth needs to be modified. @@ -1866,12 +1877,17 @@ def add_aoi_to_map( input_pois: list, input_stops: list, bbox, + merge_aoi: bool, + dis_gate: float = 30.0, projstr: Optional[str] = None, shp_path: Optional[str] = None, workers: int = 32, ): """match AOIs to lanes""" global aoi_uid, d_matcher, w_matcher, road_lane_matcher + global D_DIS_GATE, D_HUGE_GATE, W_DIS_GATE, W_HUGE_GATE, LENGTH_PER_DOOR, MAX_DOOR_NUM, AOI_GATE_OFFSET + W_DIS_GATE = dis_gate + D_DIS_GATE = W_DIS_GATE + EXTRA_DIS_GATE d_matcher, w_matcher, road_lane_matcher = ( matchers["drive"], matchers["walk"], @@ -1882,7 +1898,9 @@ def add_aoi_to_map( # raw POIs raw_pois = {doc["id"]: doc for doc in input_pois} - aois = _add_aoi(aois=input_aois, stops=input_stops, workers=workers, merge_aoi=True) + aois = _add_aoi( + aois=input_aois, stops=input_stops, workers=workers, merge_aoi=merge_aoi + ) added_input_poi = [] for _, aoi in aois.items(): added_input_poi.extend(aoi["external"].get("ex_poi_ids", [])) @@ -1903,6 +1921,7 @@ def add_sumo_aoi_to_map( input_stops: list, projstr: str, merge_aoi: bool, + dis_gate: float = 30.0, workers: int = 32, ): """for SUMO converter, match AOI to lanes""" @@ -1914,6 +1933,8 @@ def add_sumo_aoi_to_map( ) global D_DIS_GATE, D_HUGE_GATE, W_DIS_GATE, W_HUGE_GATE, LENGTH_PER_DOOR, MAX_DOOR_NUM, AOI_GATE_OFFSET global aoi_uid + W_DIS_GATE = dis_gate + D_DIS_GATE = W_DIS_GATE + EXTRA_DIS_GATE # AOI UID aoi_uid = AOI_START_ID # projection parameter diff --git a/mosstool/map/_map_util/const.py b/mosstool/map/_map_util/const.py index 74ecff0..54738b9 100644 --- a/mosstool/map/_map_util/const.py +++ b/mosstool/map/_map_util/const.py @@ -49,8 +49,9 @@ MIN_WALK_CONNECTED_COMPONENT = 5 # Minimum length of connected component of sidewalk DEFAULT_ROAD_SPLIT_LENGTH = 20 # Default road shortening length DEFAULT_JUNCTION_WALK_LANE_WIDTH = 4.0 # Default sidewalk width -D_DIS_GATE = 35 -W_DIS_GATE = 30 +# D_DIS_GATE = 35 +# W_DIS_GATE = 30 +EXTRA_DIS_GATE = 5 STOP_DIS_GATE = 30 STOP_HUGE_GATE = 50 D_HUGE_GATE = 505 diff --git a/mosstool/map/builder/builder.py b/mosstool/map/builder/builder.py index fd9b613..b8637ce 100644 --- a/mosstool/map/builder/builder.py +++ b/mosstool/map/builder/builder.py @@ -67,6 +67,8 @@ def __init__( green_time: float = 30.0, yellow_time: float = 5.0, strict_mode: bool = False, + merge_aoi: bool = True, + aoi_matching_distance_threshold: float = 30.0, output_lane_length_check: bool = False, workers: int = cpu_count(), ): @@ -88,7 +90,9 @@ def __init__( - traffic_light_mode (str): fixed time traffic-light generation mode. `green_red` means only green and red light will be generated, `green_yellow_red` means there will be yellow light between green and red light, `green_yellow_clear_red` add extra pedestrian clear red light. - green_time (float): green time - strict_mode (bool): when enabled, causes the program to exit whenever a warning occurs - - output_lane_length_check (bool): when enabled, will do value checks lane lengths in output map. + - merge_aoi (bool): merge nearby aois + - aoi_matching_distance_threshold (float): Only AOIs whose distance to the road network is less than this value will be added to the map. + - output_lane_length_check (bool): when enabled, will do value checks lane lengths in output map - yellow_time (float): yellow time - workers (int): number of workers """ @@ -113,6 +117,9 @@ def __init__( self.landuse_shp_path = landuse_shp_path self.traffic_light_min_direction_group = traffic_light_min_direction_group self.strict_mode = strict_mode + self.merge_aoi = merge_aoi + self.aoi_matching_distance_threshold = aoi_matching_distance_threshold + # TODO:加入阈值 self.output_lane_length_check = output_lane_length_check self.workers = workers self.traffic_light_mode: Union[ @@ -4106,6 +4113,8 @@ def _add_input_aoi(self): input_pois=pois, input_stops=stops, bbox=(self.min_lat, self.min_lon, self.max_lat, self.max_lon), + merge_aoi=self.merge_aoi, + dis_gate=self.aoi_matching_distance_threshold, projstr=self.proj_str, shp_path=self.landuse_shp_path, ) diff --git a/mosstool/trip/generator/__init__.py b/mosstool/trip/generator/__init__.py index 1c52338..fcddf81 100644 --- a/mosstool/trip/generator/__init__.py +++ b/mosstool/trip/generator/__init__.py @@ -2,10 +2,11 @@ from .generate_from_od import TripGenerator from .gravity import GravityGenerator from .random import PositionMode, RandomGenerator -from .template import DEFAULT_PERSON +from .template import V1_DEFAULT_PERSON,V2_DEFAULT_PERSON __all__ = [ - "DEFAULT_PERSON", + "V1_DEFAULT_PERSON", + "V2_DEFAULT_PERSON", "RandomGenerator", "PositionMode", "GravityGenerator", diff --git a/mosstool/trip/generator/_util/const.py b/mosstool/trip/generator/_util/const.py index e63b736..352ee26 100644 --- a/mosstool/trip/generator/_util/const.py +++ b/mosstool/trip/generator/_util/const.py @@ -4,7 +4,7 @@ import pycityproto.city.geo.v2.geo_pb2 as geov2 import pycityproto.city.map.v2.map_pb2 as mapv2 -import pycityproto.city.person.v1.person_pb2 as personv1 +import pycityproto.city.person.v2.person_pb2 as personv2 import pycityproto.city.trip.v2.trip_pb2 as tripv2 DIS_CAR = 1000 @@ -37,13 +37,13 @@ ] PT_START_ID = 1_0000_0000 PRIMARY_SCHOOL, JUNIOR_HIGH_SCHOOL, HIGH_SCHOOL, COLLEGE, BACHELOR, MASTER, DOCTOR = ( - personv1.EDUCATION_PRIMARY_SCHOOL, - personv1.EDUCATION_JUNIOR_HIGH_SCHOOL, - personv1.EDUCATION_HIGH_SCHOOL, - personv1.EDUCATION_COLLEGE, - personv1.EDUCATION_BACHELOR, - personv1.EDUCATION_MASTER, - personv1.EDUCATION_DOCTOR, + personv2.EDUCATION_PRIMARY_SCHOOL, + personv2.EDUCATION_JUNIOR_HIGH_SCHOOL, + personv2.EDUCATION_HIGH_SCHOOL, + personv2.EDUCATION_COLLEGE, + personv2.EDUCATION_BACHELOR, + personv2.EDUCATION_MASTER, + personv2.EDUCATION_DOCTOR, ) EDUCATION_LEVELS = [ PRIMARY_SCHOOL, @@ -57,19 +57,19 @@ # probabilities EDUCATION_STATS = [1 / len(EDUCATION_LEVELS) for _ in range(len(EDUCATION_LEVELS))] CONSUMPTION_LEVELS = [ - personv1.CONSUMPTION_LOW, - personv1.CONSUMPTION_RELATIVELY_LOW, - personv1.CONSUMPTION_MEDIUM, - personv1.CONSUMPTION_RELATIVELY_HIGH, - personv1.CONSUMPTION_HIGH, + personv2.CONSUMPTION_LOW, + personv2.CONSUMPTION_RELATIVELY_LOW, + personv2.CONSUMPTION_MEDIUM, + personv2.CONSUMPTION_RELATIVELY_HIGH, + personv2.CONSUMPTION_HIGH, ] # probabilities CONSUMPTION_STATS = [ 1 / len(CONSUMPTION_LEVELS) for _ in range(len(CONSUMPTION_LEVELS)) ] GENDERS = [ - personv1.GENDER_FEMALE, - personv1.GENDER_MALE, + personv2.GENDER_FEMALE, + personv2.GENDER_MALE, ] # probabilities GENDER_STATS = [1 / len(GENDERS) for _ in range(len(GENDERS))] diff --git a/mosstool/trip/generator/_util/utils.py b/mosstool/trip/generator/_util/utils.py index 45b19e5..f72bd86 100644 --- a/mosstool/trip/generator/_util/utils.py +++ b/mosstool/trip/generator/_util/utils.py @@ -2,16 +2,16 @@ from typing import Dict, List, Literal, Optional, Set, Tuple, Union, cast import numpy as np -from pycityproto.city.person.v1.person_pb2 import (BusAttribute, BusType, - PersonAttribute, - PersonProfile) +from pycityproto.city.person.v2.person_pb2 import (BusAttribute, BusType,Person as v2Person, + PersonAttribute) +from pycityproto.city.person.v1.person_pb2 import (BusAttribute as v1BusAttribute, BusType as v1BusType, + PersonAttribute as v1PersonAttribute, Person as v1Person) from pycityproto.city.routing.v2.routing_pb2 import (DrivingJourneyBody, Journey, JourneyType) from pycityproto.city.trip.v2.trip_pb2 import TripStop from ....map._map_util.const import * -from ....type import (AoiPosition, Consumption, Education, LanePosition, Map, - Person, Position, Schedule, Trip, TripMode) +from ....type import (AoiPosition, LanePosition, Position, Schedule, Trip, TripMode) from ....util.format_converter import dict2pb, pb2dict from .const import * @@ -243,12 +243,13 @@ def extract_HWEO_from_od_matrix( def gen_bus_drivers( person_id: int, - person_template: Person, + person_template: v2Person, depart_times: List[float], stop_duration_time: float, road_aoi_id2d_pos: Dict[Tuple[int, int], geov2.LanePosition], subline, -) -> Tuple[int, List[Person]]: + person_version:str, +) -> Tuple[int, List[v2Person]]: def _transfer_conn_road_ids( station_connection_road_ids: List[List[int]], ) -> List[int]: @@ -269,104 +270,204 @@ def _aoi_road_ids(station_connection_road_ids) -> List[int]: # road that connect to the end station cur_road_ids.append(station_connection_road_ids[-1][-1]) return cur_road_ids - - sl_id = subline.id - # basic attributes - sl_type = subline.type - bus_type = BusType.BUS_TYPE_UNSPECIFIED - if sl_type == mapv2.SUBLINE_TYPE_BUS: - sl_capacity = STATION_CAPACITY["BUS"] - sl_attributes = PT_DRIVER_ATTRIBUTES["BUS"] - bus_type = BusType.BUS_TYPE_BUS - elif sl_type == mapv2.SUBLINE_TYPE_SUBWAY: - sl_capacity = STATION_CAPACITY["SUBWAY"] - sl_attributes = PT_DRIVER_ATTRIBUTES["SUBWAY"] - bus_type = BusType.BUS_TYPE_SUBWAY - elif sl_type == mapv2.SUBLINE_TYPE_UNSPECIFIED: - sl_capacity = STATION_CAPACITY["UNSPECIFIED"] - sl_attributes = PT_DRIVER_ATTRIBUTES["UNSPECIFIED"] - bus_type = BusType.BUS_TYPE_UNSPECIFIED + if person_version=="v1": + sl_id = subline.id + # basic attributes + sl_type = subline.type + bus_type = v1BusType.BUS_TYPE_UNSPECIFIED + if sl_type == mapv2.SUBLINE_TYPE_BUS: + sl_capacity = STATION_CAPACITY["BUS"] + sl_attributes = PT_DRIVER_ATTRIBUTES["BUS"] + bus_type = v1BusType.BUS_TYPE_BUS + elif sl_type == mapv2.SUBLINE_TYPE_SUBWAY: + sl_capacity = STATION_CAPACITY["SUBWAY"] + sl_attributes = PT_DRIVER_ATTRIBUTES["SUBWAY"] + bus_type = v1BusType.BUS_TYPE_SUBWAY + elif sl_type == mapv2.SUBLINE_TYPE_UNSPECIFIED: + sl_capacity = STATION_CAPACITY["UNSPECIFIED"] + sl_attributes = PT_DRIVER_ATTRIBUTES["UNSPECIFIED"] + bus_type = v1BusType.BUS_TYPE_UNSPECIFIED + else: + raise ValueError(f"Bad Subline Type {sl_type}") + # road ids + station_connection_road_ids = [ + [rid for rid in rids.road_ids] for rids in subline.station_connection_road_ids + ] + route_road_ids = _transfer_conn_road_ids(station_connection_road_ids) + trip_stop_road_ids = _aoi_road_ids( + station_connection_road_ids + ) # stop road ids during the trip + # trip stops + aoi_ids = list(subline.aoi_ids) + home_aoi_id, end_aoi_id = aoi_ids[0], aoi_ids[-1] + trip_stop_aoi_ids = aoi_ids # stop aoi ids during the trip + trip_stop_lane_id_s = [] + for cur_road_id, cur_aoi_id in zip(trip_stop_road_ids, trip_stop_aoi_ids): + road_aoi_key = (cur_road_id, cur_aoi_id) + if road_aoi_key not in road_aoi_id2d_pos: + raise ValueError(f"bad road and AOI pair {road_aoi_key}") + d_pos = road_aoi_id2d_pos[road_aoi_key] + d_lane_id, d_s = d_pos.lane_id, d_pos.s + trip_stop_lane_id_s.append((d_lane_id, d_s)) + assert len(trip_stop_lane_id_s) == len( + trip_stop_aoi_ids + ), f"Bad PublicTransport Route at {aoi_ids}" + p_trip_stops = [] + # bus attribute + p_bus_attr = v1BusAttribute( + subline_id=sl_id, capacity=sl_capacity, type=bus_type, model="" + ) + for (d_lane_id, d_s), aoi_id in zip(trip_stop_lane_id_s, trip_stop_aoi_ids): + trip_stop = TripStop() + trip_stop.lane_position.CopyFrom(LanePosition(lane_id=d_lane_id, s=d_s)) + trip_stop.aoi_position.CopyFrom(AoiPosition(aoi_id=aoi_id)) + trip_stop.duration = stop_duration_time + p_trip_stops.append(trip_stop) + # eta for bus journey + bus_eta = sum(subline.schedules.offset_times) + sl_drivers = [] + if bus_type == BusType.BUS_TYPE_BUS: + for tm in depart_times: + p = v1Person() + p.CopyFrom(person_template) + p.id = person_id + if sl_attributes: + p.attribute.CopyFrom(dict2pb(sl_attributes, v1PersonAttribute())) + p.bus_attribute.CopyFrom(p_bus_attr) + p.home.CopyFrom(Position(aoi_position=AoiPosition(aoi_id=home_aoi_id))) + schedule = cast(Schedule, p.schedules.add()) + schedule.departure_time = tm + schedule.loop_count = 1 + trip = Trip( + mode=cast( + TripMode, + CAR, + ), + end=Position(aoi_position=AoiPosition(aoi_id=end_aoi_id)), + activity="", + model="", + trip_stops=p_trip_stops, + routes=[ + Journey( + driving=DrivingJourneyBody( + road_ids=route_road_ids, eta=bus_eta + ), + type=JourneyType.JOURNEY_TYPE_DRIVING, + ) + ], + ) + schedule.trips.append(trip) + person_id += 1 + sl_drivers.append(p) + elif bus_type == BusType.BUS_TYPE_SUBWAY: + # empty schedule + p = v1Person() + p.CopyFrom(person_template) + p.id = person_id + if sl_attributes: + p.attribute.CopyFrom(dict2pb(sl_attributes, v1PersonAttribute())) + p.bus_attribute.CopyFrom(p_bus_attr) + p.home.CopyFrom(Position(aoi_position=AoiPosition(aoi_id=home_aoi_id))) + person_id += 1 + sl_drivers.append(p) else: - raise ValueError(f"Bad Subline Type {sl_type}") - # road ids - station_connection_road_ids = [ - [rid for rid in rids.road_ids] for rids in subline.station_connection_road_ids - ] - route_road_ids = _transfer_conn_road_ids(station_connection_road_ids) - trip_stop_road_ids = _aoi_road_ids( - station_connection_road_ids - ) # stop road ids during the trip - # trip stops - aoi_ids = list(subline.aoi_ids) - home_aoi_id, end_aoi_id = aoi_ids[0], aoi_ids[-1] - trip_stop_aoi_ids = aoi_ids # stop aoi ids during the trip - trip_stop_lane_id_s = [] - for cur_road_id, cur_aoi_id in zip(trip_stop_road_ids, trip_stop_aoi_ids): - road_aoi_key = (cur_road_id, cur_aoi_id) - if road_aoi_key not in road_aoi_id2d_pos: - raise ValueError(f"bad road and AOI pair {road_aoi_key}") - d_pos = road_aoi_id2d_pos[road_aoi_key] - d_lane_id, d_s = d_pos.lane_id, d_pos.s - trip_stop_lane_id_s.append((d_lane_id, d_s)) - assert len(trip_stop_lane_id_s) == len( - trip_stop_aoi_ids - ), f"Bad PublicTransport Route at {aoi_ids}" - p_trip_stops = [] - # bus attribute - p_bus_attr = BusAttribute( - subline_id=sl_id, capacity=sl_capacity, type=bus_type, model="" - ) - for (d_lane_id, d_s), aoi_id in zip(trip_stop_lane_id_s, trip_stop_aoi_ids): - trip_stop = TripStop() - trip_stop.lane_position.CopyFrom(LanePosition(lane_id=d_lane_id, s=d_s)) - trip_stop.aoi_position.CopyFrom(AoiPosition(aoi_id=aoi_id)) - trip_stop.duration = stop_duration_time - p_trip_stops.append(trip_stop) - # eta for bus journey - bus_eta = sum(subline.schedules.offset_times) - sl_drivers = [] - if bus_type == BusType.BUS_TYPE_BUS: - for tm in depart_times: - p = Person() + sl_id = subline.id + # basic attributes + sl_type = subline.type + bus_type = BusType.BUS_TYPE_UNSPECIFIED + if sl_type == mapv2.SUBLINE_TYPE_BUS: + sl_capacity = STATION_CAPACITY["BUS"] + sl_attributes = PT_DRIVER_ATTRIBUTES["BUS"] + bus_type = BusType.BUS_TYPE_BUS + elif sl_type == mapv2.SUBLINE_TYPE_SUBWAY: + sl_capacity = STATION_CAPACITY["SUBWAY"] + sl_attributes = PT_DRIVER_ATTRIBUTES["SUBWAY"] + bus_type = BusType.BUS_TYPE_SUBWAY + elif sl_type == mapv2.SUBLINE_TYPE_UNSPECIFIED: + sl_capacity = STATION_CAPACITY["UNSPECIFIED"] + sl_attributes = PT_DRIVER_ATTRIBUTES["UNSPECIFIED"] + bus_type = BusType.BUS_TYPE_UNSPECIFIED + else: + raise ValueError(f"Bad Subline Type {sl_type}") + # road ids + station_connection_road_ids = [ + [rid for rid in rids.road_ids] for rids in subline.station_connection_road_ids + ] + route_road_ids = _transfer_conn_road_ids(station_connection_road_ids) + trip_stop_road_ids = _aoi_road_ids( + station_connection_road_ids + ) # stop road ids during the trip + # trip stops + aoi_ids = list(subline.aoi_ids) + home_aoi_id, end_aoi_id = aoi_ids[0], aoi_ids[-1] + trip_stop_aoi_ids = aoi_ids # stop aoi ids during the trip + trip_stop_lane_id_s = [] + for cur_road_id, cur_aoi_id in zip(trip_stop_road_ids, trip_stop_aoi_ids): + road_aoi_key = (cur_road_id, cur_aoi_id) + if road_aoi_key not in road_aoi_id2d_pos: + raise ValueError(f"bad road and AOI pair {road_aoi_key}") + d_pos = road_aoi_id2d_pos[road_aoi_key] + d_lane_id, d_s = d_pos.lane_id, d_pos.s + trip_stop_lane_id_s.append((d_lane_id, d_s)) + assert len(trip_stop_lane_id_s) == len( + trip_stop_aoi_ids + ), f"Bad PublicTransport Route at {aoi_ids}" + p_trip_stops = [] + # bus attribute + p_bus_attr = BusAttribute( + subline_id=sl_id, capacity=sl_capacity, type=bus_type, model="" + ) + for (d_lane_id, d_s), aoi_id in zip(trip_stop_lane_id_s, trip_stop_aoi_ids): + trip_stop = TripStop() + trip_stop.lane_position.CopyFrom(LanePosition(lane_id=d_lane_id, s=d_s)) + trip_stop.aoi_position.CopyFrom(AoiPosition(aoi_id=aoi_id)) + trip_stop.duration = stop_duration_time + p_trip_stops.append(trip_stop) + # eta for bus journey + bus_eta = sum(subline.schedules.offset_times) + sl_drivers = [] + if bus_type == BusType.BUS_TYPE_BUS: + for tm in depart_times: + p = v2Person() + p.CopyFrom(person_template) + p.id = person_id + if sl_attributes: + p.attribute.CopyFrom(dict2pb(sl_attributes, PersonAttribute())) + p.bus_attribute.CopyFrom(p_bus_attr) + p.home.CopyFrom(Position(aoi_position=AoiPosition(aoi_id=home_aoi_id))) + schedule = cast(Schedule, p.schedules.add()) + schedule.departure_time = tm + schedule.loop_count = 1 + trip = Trip( + mode=cast( + TripMode, + CAR, + ), + end=Position(aoi_position=AoiPosition(aoi_id=end_aoi_id)), + activity="", + model="", + trip_stops=p_trip_stops, + routes=[ + Journey( + driving=DrivingJourneyBody( + road_ids=route_road_ids, eta=bus_eta + ), + type=JourneyType.JOURNEY_TYPE_DRIVING, + ) + ], + ) + schedule.trips.append(trip) + person_id += 1 + sl_drivers.append(p) + elif bus_type == BusType.BUS_TYPE_SUBWAY: + # empty schedule + p = v2Person() p.CopyFrom(person_template) p.id = person_id if sl_attributes: p.attribute.CopyFrom(dict2pb(sl_attributes, PersonAttribute())) p.bus_attribute.CopyFrom(p_bus_attr) p.home.CopyFrom(Position(aoi_position=AoiPosition(aoi_id=home_aoi_id))) - schedule = cast(Schedule, p.schedules.add()) - schedule.departure_time = tm - schedule.loop_count = 1 - trip = Trip( - mode=cast( - TripMode, - CAR, - ), - end=Position(aoi_position=AoiPosition(aoi_id=end_aoi_id)), - activity="", - model="", - trip_stops=p_trip_stops, - routes=[ - Journey( - driving=DrivingJourneyBody( - road_ids=route_road_ids, eta=bus_eta - ), - type=JourneyType.JOURNEY_TYPE_DRIVING, - ) - ], - ) - schedule.trips.append(trip) person_id += 1 - sl_drivers.append(p) - elif bus_type == BusType.BUS_TYPE_SUBWAY: - # empty schedule - p = Person() - p.CopyFrom(person_template) - p.id = person_id - if sl_attributes: - p.attribute.CopyFrom(dict2pb(sl_attributes, PersonAttribute())) - p.bus_attribute.CopyFrom(p_bus_attr) - p.home.CopyFrom(Position(aoi_position=AoiPosition(aoi_id=home_aoi_id))) - person_id += 1 - sl_drivers.append(p) + return (person_id, sl_drivers) diff --git a/mosstool/trip/generator/generate_from_od.py b/mosstool/trip/generator/generate_from_od.py index d1898b6..08fded1 100644 --- a/mosstool/trip/generator/generate_from_od.py +++ b/mosstool/trip/generator/generate_from_od.py @@ -13,13 +13,14 @@ from ...map._map_util.const import * from ...type import (AoiPosition, LanePosition, Map, Person, PersonProfile, - Position, Schedule, Trip, TripMode) + Position, Schedule, Trip, TripMode, v1Person, + v1PersonProfile) from ...util.format_converter import dict2pb, pb2dict from ._util.const import * from ._util.utils import (extract_HWEO_from_od_matrix, gen_bus_drivers, gen_departure_times, gen_profiles, recalculate_trip_mode_prob) -from .template import DEFAULT_PERSON +from .template import V1_DEFAULT_PERSON, V2_DEFAULT_PERSON # from ...util.geo_match_pop import geo2pop @@ -413,7 +414,8 @@ def __init__( bus_expense: float = 5.0, bike_speed: float = 10 / 3.6, bike_penalty: float = 0.9, - template: Person = DEFAULT_PERSON, + template=None, #: Person = DEFAULT_PERSON, + person_version: Union[Literal["v1"], Literal["v2"]] = "v1", add_pop: bool = False, workers: int = cpu_count(), ): @@ -437,6 +439,7 @@ def __init__( - add_pop (bool): Add population to aois. - workers (int): number of workers. """ + self.person_version = person_version global SUBWAY_EXPENSE, BUS_EXPENSE, DRIVING_SPEED, DRIVING_PENALTY, SUBWAY_SPEED, SUBWAY_PENALTY, BUS_SPEED, BUS_PENALTY, BIKE_SPEED, BIKE_PENALTY, PARKING_FEE SUBWAY_EXPENSE, BUS_EXPENSE = subway_expense, bus_expense DRIVING_SPEED, DRIVING_PENALTY, PARKING_FEE = ( @@ -452,6 +455,10 @@ def __init__( self.add_pop = add_pop self.projector = pyproj.Proj(m.header.projection) self.workers = workers + if person_version == "v1": + template = V1_DEFAULT_PERSON + else: + template = V2_DEFAULT_PERSON self.template = template self.template.ClearField("schedules") self.template.ClearField("home") @@ -683,12 +690,18 @@ def _generate_mobi( activities, ) in enumerate(raw_persons): times = np.array(times) * 3600 # hour->second - p = Person() + if self.person_version == "v1": + p = v1Person() + else: + p = Person() p.CopyFrom(self.template) p.id = agent_id p.home.CopyFrom(Position(aoi_position=AoiPosition(aoi_id=person_home))) p.work.CopyFrom(Position(aoi_position=AoiPosition(aoi_id=person_work))) - p.profile.CopyFrom(dict2pb(a_profile, PersonProfile())) + if self.person_version == "v1": + p.profile.CopyFrom(dict2pb(a_profile, v1PersonProfile())) + else: + p.profile.CopyFrom(dict2pb(a_profile, PersonProfile())) for time, aoi_id, trip_mode, activity, trip_model in zip( times, aoi_list[1:], trip_modes, activities, trip_models ): @@ -814,6 +827,7 @@ def generate_public_transport_drivers( stop_duration_time, road_aoi_id2d_pos, sl, + self.person_version ) self.persons.extend(generated_drivers) return self.persons diff --git a/mosstool/trip/generator/random.py b/mosstool/trip/generator/random.py index 26ca1af..b06eba6 100644 --- a/mosstool/trip/generator/random.py +++ b/mosstool/trip/generator/random.py @@ -1,15 +1,16 @@ from enum import Enum -from typing import List, Optional, Tuple, Union, cast +from typing import List, Literal, Optional, Tuple, Union, cast import numpy as np from pycityproto.city.geo.v2.geo_pb2 import AoiPosition, LanePosition, Position from pycityproto.city.map.v2.map_pb2 import Aoi, Lane, LaneType, Map -from pycityproto.city.person.v1.person_pb2 import Person +from pycityproto.city.person.v1.person_pb2 import Person as v1Person +from pycityproto.city.person.v2.person_pb2 import Person as v2Person from pycityproto.city.trip.v2.trip_pb2 import Schedule, Trip, TripMode -from ._util.utils import is_walking -from .template import DEFAULT_PERSON from ...map._map_util.const import JUNC_START_ID +from ._util.utils import is_walking +from .template import V1_DEFAULT_PERSON, V2_DEFAULT_PERSON __all__ = ["PositionMode", "RandomGenerator"] @@ -29,7 +30,9 @@ def __init__( m: Map, position_modes: List[PositionMode], trip_mode: TripMode, - template: Person = DEFAULT_PERSON, + template=None, + # Person = DEFAULT_PERSON, + person_version: Union[Literal["v1"], Literal["v2"]] = "v1", ): """ Args: @@ -38,6 +41,11 @@ def __init__( - trip_mode (TripMode): The target trip mode. - template (Person): The template of generated person object, whose `schedules`, `home` will be replaced and others will be copied. """ + self.person_version = person_version + if person_version == "v1": + template = V1_DEFAULT_PERSON + else: + template = V2_DEFAULT_PERSON self.m = m self.modes = position_modes if len(self.modes) <= 1: @@ -85,7 +93,7 @@ def uniform( schedule_interval_range: Tuple[float, float], seed: Optional[int] = None, start_id: Optional[int] = None, - ) -> List[Person]: + ) -> List[v1Person]: """ Generate a person object by uniform random sampling @@ -103,7 +111,10 @@ def uniform( np.random.seed(seed) persons = [] for i in range(num): - p = Person() + if self.person_version == "v1": + p = v1Person() + else: + p = v2Person() p.CopyFrom(self.template) if start_id is not None: p.id = start_id + i diff --git a/mosstool/trip/generator/template.py b/mosstool/trip/generator/template.py index 5445cad..2a836cc 100644 --- a/mosstool/trip/generator/template.py +++ b/mosstool/trip/generator/template.py @@ -1,17 +1,45 @@ -from pycityproto.city.person.v1.person_pb2 import ( - Person, - PersonAttribute, - VehicleAttribute, - PedestrianAttribute, - BikeAttribute, -) +from pycityproto.city.person.v1.person_pb2 import \ + BikeAttribute as v1BikeAttribute +from pycityproto.city.person.v1.person_pb2 import \ + PedestrianAttribute as v1PedestrianAttribute +from pycityproto.city.person.v1.person_pb2 import Person as v1Person +from pycityproto.city.person.v1.person_pb2 import \ + PersonAttribute as v1PersonAttribute +from pycityproto.city.person.v1.person_pb2 import \ + VehicleAttribute as v1VehicleAttribute +from pycityproto.city.person.v2.person_pb2 import (BikeAttribute, + EmissionAttribute, + PedestrianAttribute, Person as v2Person, + PersonAttribute, + VehicleAttribute, + VehicleEngineEfficiency, + VehicleEngineType) __all__ = [ - "DEFAULT_PERSON", + "V1_DEFAULT_PERSON", + "V2_DEFAULT_PERSON", ] -DEFAULT_PERSON = Person( - attribute=PersonAttribute( +V1_DEFAULT_PERSON = v1Person( + attribute=v1PersonAttribute( + length=5, + width=2, + max_speed=150 / 3.6, + max_acceleration=3, + max_braking_acceleration=-10, + usual_acceleration=2, + usual_braking_acceleration=-4.5, + ), + vehicle_attribute=v1VehicleAttribute( + lane_change_length=10, + min_gap=1, + ), + pedestrian_attribute=v1PedestrianAttribute(speed=1.34), + bike_attribute=v1BikeAttribute(speed=5), +) +V2_DEFAULT_PERSON = v2Person( + attribute=PersonAttribute(), + vehicle_attribute=VehicleAttribute( length=5, width=2, max_speed=150 / 3.6, @@ -19,8 +47,21 @@ max_braking_acceleration=-10, usual_acceleration=2, usual_braking_acceleration=-4.5, + headway=1.5, + lane_max_speed_recognition_deviation=1.0, + lane_change_length=10, + min_gap=1, + emission_attribute=EmissionAttribute( + weight=2100, + type=VehicleEngineType.VEHICLE_ENGINE_TYPE_FUEL, + coefficient_drag=0.251, + lambda_s=0.29, + frontal_area=2.52, + fuel_efficiency=VehicleEngineEfficiency( + energy_conversion_efficiency=0.27 * 0.049 + ), + ), ), - vehicle_attribute=VehicleAttribute(lane_change_length=10, min_gap=1), pedestrian_attribute=PedestrianAttribute(speed=1.34), bike_attribute=BikeAttribute(speed=5), ) diff --git a/mosstool/trip/route/preroute.py b/mosstool/trip/route/preroute.py index 017c833..460d902 100644 --- a/mosstool/trip/route/preroute.py +++ b/mosstool/trip/route/preroute.py @@ -1,7 +1,8 @@ import logging from typing import cast -from pycityproto.city.person.v1.person_pb2 import Person +from pycityproto.city.person.v1.person_pb2 import Person as v1Person +from pycityproto.city.person.v2.person_pb2 import Person as v2Person from pycityproto.city.routing.v2.routing_pb2 import RouteType from pycityproto.city.routing.v2.routing_service_pb2 import GetRouteRequest from pycityproto.city.trip.v2.trip_pb2 import Schedule, TripMode @@ -19,8 +20,11 @@ async def pre_route( - client: RoutingClient, person: Person, in_place: bool = False -) -> Person: + client: RoutingClient, + person: v2Person, + in_place: bool = False, + person_version: str = "v1", +) -> v2Person: """ Fill in the route of the person's all schedules. The function will REMOVE all schedules that can not be routed. @@ -34,9 +38,12 @@ async def pre_route( - None """ if not in_place: - p = Person() - p.CopyFrom(person) - person = p + if person_version == "v1": + p = v1Person() + else: + p = v2Person() + p.CopyFrom(person) # type:ignore + person = p # type:ignore start = person.home departure_time = None all_schedules = list(person.schedules) diff --git a/mosstool/trip/sumo/route.py b/mosstool/trip/sumo/route.py index 9ef9b6e..583950e 100644 --- a/mosstool/trip/sumo/route.py +++ b/mosstool/trip/sumo/route.py @@ -6,7 +6,6 @@ import numpy as np import pycityproto.city.map.v2.map_pb2 as mapv2 -import pycityproto.city.person.v1.person_pb2 as personv1 import pycityproto.city.routing.v2.routing_pb2 as routingv2 import pycityproto.city.trip.v2.trip_pb2 as tripv2 from pycityproto.city.map.v2.map_pb2 import Map @@ -136,6 +135,7 @@ def __init__( # https://sumo.dlr.de/docs/Definition_of_Vehicles%2C_Vehicle_Types%2C_and_Routes.html#car-following_models # model_name = v.getAttribute("carFollowModel") if v.hasAttribute("carFollowModel") else "IDM" self._vtype[vid] = ( + {}, { "length": length, "width": width, @@ -144,8 +144,6 @@ def __init__( "max_braking_acceleration": max_dec, "usual_acceleration": usual_acc, "usual_braking_acceleration": usual_dec, - }, - { "lane_change_length": LC_length, "min_gap": min_gap, }, @@ -659,7 +657,8 @@ def _route_trips_to_person( def convert_route(self): self.agent_uid = 0 - DEFAULT_AGENT_ATTRIBUTE = { + DEFAULT_AGENT_ATTRIBUTE = {} + DEFAULT_VEHICLE_ATTRIBUTE = { "length": 5, "width": 2, "max_speed": 41.6666666667, @@ -667,19 +666,11 @@ def convert_route(self): "max_braking_acceleration": -10, "usual_acceleration": 2, "usual_braking_acceleration": -4.5, - } - DEFAULT_VEHICLE_ATTRIBUTE = { - "lane_change_length": 10, - "min_gap": 1, - } - DEFAULT_PEDESTRIAN_ATTRIBUTE = { - "lane_change_length": 10, - "min_gap": 1, - } - DEFAULT_BIKE_ATTRIBUTE = { "lane_change_length": 10, "min_gap": 1, } + DEFAULT_PEDESTRIAN_ATTRIBUTE = {"speed": 1.34} + DEFAULT_BIKE_ATTRIBUTE = {"speed": 5} DEFAULT_AGENT_TYPE = "AGENT_TYPE_PRIVATE_CAR" # Route contains the edges that all vehicles pass through, that is, the complete trajectory diff --git a/mosstool/type/__init__.py b/mosstool/type/__init__.py index a6e3b44..c602f35 100644 --- a/mosstool/type/__init__.py +++ b/mosstool/type/__init__.py @@ -4,26 +4,26 @@ # TODO: pycityproto version checking -from pycityproto.city.geo.v2.geo_pb2 import ( - AoiPosition, - LanePosition, - LongLatPosition, - Position, -) -from pycityproto.city.map.v2.map_pb2 import Aoi, AoiType, Lane, LaneTurn, LaneType, Map -from pycityproto.city.person.v1.person_pb2 import ( - Consumption, - Education, - Gender, - Person, - PersonProfile, - Persons, -) -from pycityproto.city.routing.v2.routing_pb2 import Journey, JourneyType, DrivingJourneyBody -from pycityproto.city.routing.v2.routing_service_pb2 import ( - GetRouteRequest, - GetRouteResponse, -) +from pycityproto.city.geo.v2.geo_pb2 import (AoiPosition, LanePosition, + LongLatPosition, Position) +from pycityproto.city.map.v2.map_pb2 import (Aoi, AoiType, Lane, LaneTurn, + LaneType, Map) +from pycityproto.city.person.v1.person_pb2 import Consumption as v1Consumption +from pycityproto.city.person.v1.person_pb2 import Education as v1Education +from pycityproto.city.person.v1.person_pb2 import Gender as v1Gender +from pycityproto.city.person.v1.person_pb2 import Person as v1Person +from pycityproto.city.person.v1.person_pb2 import Person +from pycityproto.city.person.v1.person_pb2 import Persons +from pycityproto.city.person.v1.person_pb2 import \ + PersonProfile as v1PersonProfile +from pycityproto.city.person.v1.person_pb2 import Persons as v1Persons +from pycityproto.city.person.v2.person_pb2 import (Consumption, Education, + Gender, Person as v2Person, + PersonProfile, Persons as v2Persons) +from pycityproto.city.routing.v2.routing_pb2 import (DrivingJourneyBody, + Journey, JourneyType) +from pycityproto.city.routing.v2.routing_service_pb2 import (GetRouteRequest, + GetRouteResponse) from pycityproto.city.trip.v2.trip_pb2 import Schedule, Trip, TripMode __all__ = [ diff --git a/pyproject.toml b/pyproject.toml index 14caee3..ff96e8d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "mosstool" -version = "0.2.42" +version = "0.2.43" description = "MObility Simulation System toolbox " authors = ["Jun Zhang "] license = "MIT"