diff --git a/examples/gen_pt_drivers.py b/examples/gen_pt_drivers.py index 63642e4..59f70a7 100644 --- a/examples/gen_pt_drivers.py +++ b/examples/gen_pt_drivers.py @@ -6,11 +6,10 @@ with open("data/temp/srt.map_with_pt.pb", "rb") as f: m = Map() m.ParseFromString(f.read()) -tg = TripGenerator( - m=m, - template_func=default_bus_template_generator, +tg = TripGenerator(m=m) +bus_drivers = tg.generate_public_transport_drivers( + template_func=default_bus_template_generator ) -bus_drivers = tg.generate_public_transport_drivers() persons_output_path = "data/temp/bus_drivers.pb" pb = Persons(persons=bus_drivers) with open(persons_output_path, "wb") as f: diff --git a/examples/random_persons.py b/examples/random_persons.py index 39b1661..1edaee1 100644 --- a/examples/random_persons.py +++ b/examples/random_persons.py @@ -1,5 +1,5 @@ from mosstool.trip.generator import (PositionMode, RandomGenerator, - default_vehicle_template_generator) + default_person_template_generator) from mosstool.trip.route import RoutingClient, pre_route from mosstool.type import Map, Person, Persons, TripMode from mosstool.util.format_converter import pb2json @@ -13,7 +13,7 @@ async def main(): m, [PositionMode.LANE, PositionMode.LANE], TripMode.TRIP_MODE_DRIVE_ONLY, - template_func=default_vehicle_template_generator, + template_func=default_person_template_generator, ) persons = rg.uniform( num=100, diff --git a/mosstool/trip/generator/__init__.py b/mosstool/trip/generator/__init__.py index 8cd718b..75513c0 100644 --- a/mosstool/trip/generator/__init__.py +++ b/mosstool/trip/generator/__init__.py @@ -6,14 +6,14 @@ ProbabilisticTemplateGenerator, UniformTemplateGenerator, default_bus_template_generator, - default_vehicle_template_generator) + default_person_template_generator) __all__ = [ "ProbabilisticTemplateGenerator", "GaussianTemplateGenerator", "UniformTemplateGenerator", "CalibratedTemplateGenerator", - "default_vehicle_template_generator", + "default_person_template_generator", "default_bus_template_generator", "RandomGenerator", "PositionMode", diff --git a/mosstool/trip/generator/_util/const.py b/mosstool/trip/generator/_util/const.py index 8189cc8..400e37a 100644 --- a/mosstool/trip/generator/_util/const.py +++ b/mosstool/trip/generator/_util/const.py @@ -40,13 +40,14 @@ ] TRIP_MODES_DICT = { BUS: "bus", - BUS_SUBWAY:"bus_subway", - SUBWAY:"subway", + BUS_SUBWAY: "bus_subway", + SUBWAY: "subway", CAR: "drive", TAXI: "taxi", WALK: "walk", } PT_START_ID = 1_0000_0000 +TAXI_START_ID = 2_0000_0000 PRIMARY_SCHOOL, JUNIOR_HIGH_SCHOOL, HIGH_SCHOOL, COLLEGE, BACHELOR, MASTER, DOCTOR = ( personv2.EDUCATION_PRIMARY_SCHOOL, personv2.EDUCATION_JUNIOR_HIGH_SCHOOL, diff --git a/mosstool/trip/generator/_util/utils.py b/mosstool/trip/generator/_util/utils.py index ad388c8..05589ed 100644 --- a/mosstool/trip/generator/_util/utils.py +++ b/mosstool/trip/generator/_util/utils.py @@ -6,6 +6,7 @@ import numpy as np from pycityproto.city.person.v2.person_pb2 import (BusAttribute, BusType, Person, PersonAttribute, + PersonType, VehicleAttribute) from pycityproto.city.routing.v2.routing_pb2 import (DrivingJourneyBody, Journey, JourneyType) @@ -356,7 +357,7 @@ def _aoi_road_ids(station_connection_road_ids) -> List[int]: p_trip_stops.append(trip_stop) # eta for bus journey bus_eta = sum(subline.schedules.offset_times) - sl_drivers = [] + sl_drivers: List[Person] = [] if bus_type == BusType.BUS_TYPE_BUS: for tm in depart_times: p = Person() @@ -396,3 +397,29 @@ def _aoi_road_ids(station_connection_road_ids) -> List[int]: person_id += 1 return (person_id, sl_drivers) + + +def gen_taxi_drivers( + person_id: int, + person_template_generator: Callable[[], Person], + home_position: Union[LanePosition, AoiPosition], + num: int = 1, +) -> Tuple[int, List[Person]]: + taxi_drivers: List[Person] = [] + for _ in range(num): + p = Person() + p.CopyFrom(person_template_generator()) + p.id = person_id + p.type = PersonType.PERSON_TYPE_TAXI + if isinstance(home_position, LanePosition): + p.home.CopyFrom(Position(lane_position=home_position)) + elif isinstance(home_position, AoiPosition): + p.home.CopyFrom(Position(aoi_position=home_position)) + else: + logging.warning( + f"Invalid type of `parking_position` {type(home_position).__name__}!" + ) + continue + taxi_drivers.append(p) + person_id += 1 + return (person_id, taxi_drivers) diff --git a/mosstool/trip/generator/generate_from_od.py b/mosstool/trip/generator/generate_from_od.py index ce12bf2..a1ca15c 100644 --- a/mosstool/trip/generator/generate_from_od.py +++ b/mosstool/trip/generator/generate_from_od.py @@ -18,9 +18,9 @@ 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, + gen_departure_times, gen_profiles, gen_taxi_drivers, recalculate_trip_mode_prob, recalculate_trip_modes) -from .template import default_vehicle_template_generator +from .template import default_person_template_generator # from ...util.geo_match_pop import geo2pop @@ -417,7 +417,7 @@ def __init__( bus_expense: float = 5.0, bike_speed: float = 10 / 3.6, bike_penalty: float = 0.0, - template_func: Callable[[], Person] = default_vehicle_template_generator, + template_func: Callable[[], Person] = default_person_template_generator, add_pop: bool = False, multiprocessing_chunk_size: int = 500, workers: int = cpu_count(), @@ -493,6 +493,7 @@ def _read_aois(self): ] for p in i.positions ) + a["has_driving_gates"] = len(i.driving_gates) > 0 aois.append(a) def get_aoi_catg(urban_land_use: str): @@ -775,7 +776,7 @@ def generate_persons( self._generate_mobi(agent_num, area_pops, person_profiles, seed) return self.persons - def _get_driving_pos_dict(self) -> Dict[Tuple[int, int], geov2.LanePosition]: + def _get_driving_pos_dict(self) -> Dict[Tuple[int, int], LanePosition]: road_aoi_id2d_pos = {} road_id2d_lane_ids = {} lane_id2parent_road_id = {} @@ -808,11 +809,13 @@ def _get_driving_pos_dict(self) -> Dict[Tuple[int, int], geov2.LanePosition]: def generate_public_transport_drivers( self, + template_func: Optional[Callable[[], Person]] = None, stop_duration_time: float = 30.0, seed: int = 0, ) -> List[Person]: """ Args: + - template_func (Optional[Callable[[],Person]]): The template function of generated person object, whose `schedules`, `home` will be replaced and others will be copied. If not provided, the `temp_func` provided in `__init__` will be utilized. - stop_duration_time (float): The duration time (in second) for bus at each stop. - seed (int): The random seed. @@ -822,13 +825,14 @@ def generate_public_transport_drivers( self.persons = [] road_aoi_id2d_pos = self._get_driving_pos_dict() person_id = PT_START_ID + _template = template_func if template_func is not None else self.template for sl in self.m.sublines: departure_times = list(sl.schedules.departure_times) if not sl.type in {mapv2.SUBLINE_TYPE_BUS, mapv2.SUBLINE_TYPE_SUBWAY}: continue person_id, generated_drivers = gen_bus_drivers( person_id, - self.template, + _template, departure_times, stop_duration_time, road_aoi_id2d_pos, @@ -1003,3 +1007,52 @@ def fill_person_schedules( self._generate_schedules(input_persons, seed) return self.persons + + def generate_taxi_drivers( + self, + template_func: Optional[Callable[[], Person]] = None, + parking_positions: Optional[List[Union[LanePosition, AoiPosition]]] = None, + agent_num: Optional[int] = None, + seed: int = 0, + ) -> List[Person]: + """ + Args: + - template_func (Optional[Callable[[],Person]]): The template function of generated person object, whose `schedules`, `home` will be replaced and others will be copied. If not provided, the `temp_func` provided in `__init__` will be utilized. + - parking_positions (Optional[List[Union[LanePosition,AoiPosition]]]): The parking positions of each taxi. + - agent_num (Optional[int]): The taxi driver num. + - seed (int): The random seed. + + Returns: + - List[Person]: The generated driver objects. + """ + self.persons = [] + person_id = TAXI_START_ID + _template = template_func if template_func is not None else self.template + self._read_aois() + if parking_positions is not None: + logging.info(f"") + _taxi_home_positions = parking_positions + elif agent_num is not None: + logging.info(f"") + if not agent_num >= 1: + logging.warning("agent_num should >=1") + return [] + rng = np.random.default_rng(seed) + has_driving_aoi_ids = [a["id"] for a in self.aois if a["has_driving_gates"]] + _taxi_home_positions = [ + AoiPosition(aoi_id=_id) + for _id in rng.choice(has_driving_aoi_ids, int(agent_num)) + ] + else: + logging.warning( + "Either `agent_num` or `parking_positions` should be provided!" + ) + return [] + for _pos in _taxi_home_positions: + person_id, generated_drivers = gen_taxi_drivers( + person_id, + _template, + _pos, + ) + self.persons.extend(generated_drivers) + return self.persons diff --git a/mosstool/trip/generator/random.py b/mosstool/trip/generator/random.py index 83bfc7d..3edfe9a 100644 --- a/mosstool/trip/generator/random.py +++ b/mosstool/trip/generator/random.py @@ -9,7 +9,7 @@ from ...map._map_util.const import JUNC_START_ID from ._util.utils import is_walking -from .template import default_vehicle_template_generator +from .template import default_person_template_generator __all__ = ["PositionMode", "RandomGenerator"] @@ -29,7 +29,7 @@ def __init__( m: Map, position_modes: List[PositionMode], trip_mode: TripMode, - template_func: Callable[[], Person] = default_vehicle_template_generator, + template_func: Callable[[], Person] = default_person_template_generator, ): """ Args: diff --git a/mosstool/trip/generator/template.py b/mosstool/trip/generator/template.py index 5f94c8d..266f944 100644 --- a/mosstool/trip/generator/template.py +++ b/mosstool/trip/generator/template.py @@ -4,7 +4,7 @@ from pycityproto.city.person.v2.person_pb2 import (BikeAttribute, EmissionAttribute, PedestrianAttribute, Person, - PersonAttribute, + PersonAttribute, PersonType, VehicleAttribute, VehicleEngineEfficiency, VehicleEngineType) @@ -15,15 +15,16 @@ CALIBRATED_MAX_ACC_VALUES) __all__ = [ - "default_vehicle_template_generator", + "default_person_template_generator", "default_bus_template_generator", "ProbabilisticTemplateGenerator", ] -def default_vehicle_template_generator() -> Person: +def default_person_template_generator() -> Person: return Person( attribute=PersonAttribute(), + type=PersonType.PERSON_TYPE_NORMAL, vehicle_attribute=VehicleAttribute( length=5, width=2, @@ -57,6 +58,7 @@ def default_vehicle_template_generator() -> Person: def default_bus_template_generator() -> Person: return Person( attribute=PersonAttribute(), + type=PersonType.PERSON_TYPE_NORMAL, vehicle_attribute=VehicleAttribute( length=15, width=2, @@ -124,7 +126,7 @@ def __init__( """ self.template_p = template if self.template_p is None: - self.template_p = default_vehicle_template_generator() + self.template_p = default_person_template_generator() self.template_p.ClearField("schedules") # max speed self.max_speed_values = max_speed_values @@ -317,7 +319,7 @@ def __init__( """ self.template_p = template if self.template_p is None: - self.template_p = default_vehicle_template_generator() + self.template_p = default_person_template_generator() self.template_p.ClearField("schedules") # max speed self.max_speed_mean = max_speed_mean @@ -429,7 +431,7 @@ def __init__( """ self.template_p = template if self.template_p is None: - self.template_p = default_vehicle_template_generator() + self.template_p = default_person_template_generator() self.template_p.ClearField("schedules") # max speed self.max_speed_min = max_speed_min @@ -515,7 +517,7 @@ def __init__(self, seed: int = 0, template: Optional[Person] = None) -> None: """ self.template_p = template if self.template_p is None: - self.template_p = default_vehicle_template_generator() + self.template_p = default_person_template_generator() self.template_p.ClearField("schedules") # radom engine self.rng = np.random.default_rng(seed) diff --git a/mosstool/type/__init__.py b/mosstool/type/__init__.py index c142c85..67273f2 100644 --- a/mosstool/type/__init__.py +++ b/mosstool/type/__init__.py @@ -9,7 +9,7 @@ from pycityproto.city.map.v2.map_pb2 import (Aoi, AoiType, Lane, LaneTurn, LaneType, Map) from pycityproto.city.person.v2.person_pb2 import (Consumption, Education, - Gender, Person, + Gender, Person,PersonType, PersonProfile, Persons) from pycityproto.city.routing.v2.routing_pb2 import (DrivingJourneyBody, Journey, JourneyType) @@ -23,6 +23,7 @@ "LaneType", "LaneTurn", "Person", + "PersonType", "Persons", "TripMode", "Position", diff --git a/pyproject.toml b/pyproject.toml index 3a896fa..11791dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "mosstool" -version = "1.0.23" +version = "1.0.24" description = "MObility Simulation System toolbox " authors = ["Jun Zhang ","Junbo Yan "] license = "MIT"