mosstool.trip.sumo
SUMO Route Converting Tools
class
RouteConverter:
18class RouteConverter: 19 def __init__( 20 self, 21 converted_map: Map, 22 sumo_id_mappings: dict, 23 route_path: str, 24 additional_path: Optional[str] = None, 25 seed: Optional[int] = 0, 26 ): 27 """ 28 Args: 29 - converted_map: The converted map from SUMO network. 30 - sumo_id_mappings: The mapping from SUMO id to the unique id in the converted map. 31 - route_path: The path to the SUMO route file. 32 - additional_path: The path to the additional file containing bus stops, charging stations, and parking areas. 33 - seed: The random seed. 34 """ 35 if seed is not None: 36 random.seed(seed) 37 self._additional_path = additional_path # additional file with "busStop","chargingStation","parkingArea" 38 self._id2uid = sumo_id_mappings 39 m = converted_map 40 logging.info("Reading converted map") 41 self._lanes = {} 42 self._juncs = {} 43 self._roads = {} 44 for l in m.lanes: 45 lid = l.id 46 pres = l.predecessors 47 sucs = l.successors 48 self._lanes[lid] = { 49 "type": l.type, 50 "geo": LineString([[p.x, p.y] for p in l.center_line.nodes]), 51 "in_lids": [p.id for p in pres], 52 "out_lids": [s.id for s in sucs], 53 "parent_id": l.parent_id, 54 "length": l.length, 55 } 56 for j in m.junctions: 57 jid = j.id 58 self._juncs[jid] = { 59 "lane_ids": j.lane_ids, 60 } 61 for r in m.roads: 62 rid = r.id 63 self._roads[rid] = { 64 "lane_ids": r.lane_ids, 65 "length": self._lanes[r.lane_ids[len(r.lane_ids) // 2]]["length"], 66 "driving_lane_ids": [ 67 lid 68 for lid in r.lane_ids 69 if self._lanes[lid]["type"] == mapv2.LANE_TYPE_DRIVING 70 ], 71 "walking_lane_ids": [ 72 lid 73 for lid in r.lane_ids 74 if self._lanes[lid]["type"] == mapv2.LANE_TYPE_WALKING 75 ], 76 } 77 logging.info(f"Reading route from {route_path}") 78 dom_tree = parse(route_path) 79 # get the root node 80 root_node = dom_tree.documentElement 81 # read SUMO .route.xml 82 self._vtype = ( 83 {} 84 ) # vehicle_id -> (agent_attribute,vehicle_attribute,pedestrian_attribute,bike_attribute,agent_type,) 85 self._routes = root_node.getElementsByTagName("route") 86 self._trips = root_node.getElementsByTagName("trip") 87 self._flows = root_node.getElementsByTagName("flow") 88 self._intervals = root_node.getElementsByTagName( 89 "interval" 90 ) # interval contains multiple `flows` 91 self._vehicles = root_node.getElementsByTagName("vehicle") 92 # output data 93 self._output_agents = [] 94 for v in root_node.getElementsByTagName("vType"): 95 vid = v.getAttribute("id") 96 max_acc = ( 97 np.float64(v.getAttribute("accel")) if v.hasAttribute("accel") else 3.0 98 ) 99 max_dec = ( 100 -np.float64(v.getAttribute("decel")) 101 if v.hasAttribute("decel") 102 else -4.5 103 ) 104 length = ( 105 np.float64(v.getAttribute("length")) 106 if v.hasAttribute("length") 107 else 5.0 108 ) 109 max_speed = ( 110 np.float64(v.getAttribute("maxSpeed")) 111 if v.hasAttribute("maxSpeed") 112 else 41.6666666667 113 ) 114 width = ( 115 np.float64(v.getAttribute("width")) if v.hasAttribute("width") else 2.0 116 ) 117 min_gap = ( 118 np.float64(v.getAttribute("minGap")) 119 if v.hasAttribute("minGap") 120 else 1.0 121 ) 122 v_class = v.getAttribute("vClass") if v.hasAttribute("vClass") else "" 123 if v_class == "pedestrian": 124 agent_type = "AGENT_TYPE_PERSON" 125 elif v_class == "bus": 126 agent_type = "AGENT_TYPE_BUS" 127 elif v_class == "bicycle": 128 agent_type = "AGENT_TYPE_BIKE" 129 else: 130 agent_type = "AGENT_TYPE_PRIVATE_CAR" 131 132 usual_acc = 2.0 133 usual_dec = -4.5 134 LC_length = 2 * length 135 # TODO: add other car-following-model 136 # https://sumo.dlr.de/docs/Definition_of_Vehicles%2C_Vehicle_Types%2C_and_Routes.html#car-following_models 137 # model_name = v.getAttribute("carFollowModel") if v.hasAttribute("carFollowModel") else "IDM" 138 self._vtype[vid] = ( 139 {}, 140 { 141 "length": length, 142 "width": width, 143 "max_speed": max_speed, 144 "max_acceleration": max_acc, 145 "max_braking_acceleration": max_dec, 146 "usual_acceleration": usual_acc, 147 "usual_braking_acceleration": usual_dec, 148 "lane_change_length": LC_length, 149 "min_gap": min_gap, 150 }, 151 { 152 "speed": 1.34, 153 }, 154 { 155 "speed": 5.0, 156 }, 157 agent_type, 158 ) 159 self._additional_stops = {} 160 if self._additional_path: 161 add_dom_tree = parse(self._additional_path) 162 add_root_node = add_dom_tree.documentElement 163 for stop_type in ["busStop", "chargingStation", "parkingArea"]: 164 for stop in add_root_node.getElementsByTagName(stop_type): 165 stop_id = stop.getAttribute("id") 166 stop_name = ( 167 stop.getAttribute("name") if stop.hasAttribute("name") else "" 168 ) 169 if stop.getAttribute("lane") in self._id2uid.keys(): 170 stop_lid = self._id2uid[stop.getAttribute("lane")] 171 stop_lane = self._lanes[stop_lid] 172 start_pos = ( 173 np.float64(stop.getAttribute("startPos")) 174 if stop.hasAttribute("startPos") 175 else 0.1 * stop_lane["length"] 176 ) 177 if start_pos < 0: 178 start_pos += stop_lane["length"] 179 end_pos = ( 180 np.float64(stop.getAttribute("endPos")) 181 if stop.hasAttribute("endPos") 182 else 0.9 * stop_lane["length"] 183 ) 184 if end_pos < 0: 185 end_pos += stop_lane["length"] 186 stop_s = (end_pos + start_pos) / 2 187 stop_s = np.clip( 188 stop_s, 0.1 * stop_lane["length"], 0.9 * stop_lane["length"] 189 ) 190 veh_stop = { 191 "lane_position": { 192 "lane_id": stop_lid, 193 "s": stop_s, 194 } 195 } 196 parent_rid = stop_lane["parent_id"] 197 self._additional_stops[stop_id] = (veh_stop, parent_rid) 198 else: 199 logging.warning(f"Invalid stop {stop_id} {stop_name}!") 200 201 def _convert_time(self, time_str: str) -> np.float64: 202 if ":" not in time_str: 203 return np.float64(time_str) 204 converted_time = np.float64(0) 205 times = time_str.split(":") 206 t_factor = 1.0 207 for t in times[::-1][:3]: 208 converted_time += t_factor * np.float64(t) 209 t_factor *= 60 210 return converted_time 211 212 def _convert_route_trips( 213 self, edges: list, repeat: int, cycle_time: np.float64, rid2stop: dict 214 ): 215 route_trips = [] # Road ids separated by stop 216 last_stop_rid = None # Ensure road ids contain the start and end points 217 for n_repeat in range(repeat + 1): 218 road_ids = [] 219 for eid in edges: 220 if not eid in self._id2uid.keys(): # Indicates junction lane 221 continue 222 else: 223 if last_stop_rid: 224 road_ids.append(last_stop_rid) 225 last_stop_rid = None 226 rid = self._id2uid[eid] 227 road_ids.append(rid) 228 if rid in rid2stop.keys(): 229 stop = rid2stop[rid] 230 if stop["until"]: 231 stop["until"] += n_repeat * cycle_time 232 route_trips.append( 233 { 234 "road_ids": road_ids, 235 "stop": stop, 236 } 237 ) 238 last_stop_rid = rid 239 road_ids = [] 240 if road_ids: 241 route_trips.append( 242 { 243 "road_ids": road_ids, 244 "stop": None, 245 } 246 ) 247 return route_trips 248 249 def _process_route_trips( 250 self, 251 t: minidom.Element, 252 route_trips: list, 253 trip_id: int, 254 pre_veh_end: dict, 255 TRIP_MODE: int, 256 ROAD_LANE_TYPE: Union[Literal["walking_lane_ids"], Literal["driving_lane_ids"]], 257 SPEED: float, 258 departure: np.float64, 259 trip_type: Union[Literal["trip"], Literal["flow"], Literal["vehicle"]] = "flow", 260 ): 261 schedules = [] 262 for i, route_trip in enumerate(route_trips): 263 road_ids = route_trip["road_ids"] 264 stop = route_trip["stop"] 265 from_rid = road_ids[0] 266 from_road = self._roads[from_rid] 267 to_rid = road_ids[-1] 268 to_road = self._roads[to_rid] 269 if not stop: 270 veh_end = self._get_trip_position( 271 t, 272 trip_id, 273 to_road, 274 to_rid, 275 ROAD_LANE_TYPE, 276 trip_type=trip_type, 277 attribute="arrivalLane", 278 ) 279 else: 280 veh_end = stop["veh_end"] 281 if TRIP_MODE in { 282 tripv2.TRIP_MODE_WALK_ONLY, 283 tripv2.TRIP_MODE_BIKE_WALK, 284 tripv2.TRIP_MODE_BUS_WALK, 285 }: 286 pre_lid = pre_veh_end["lane_position"]["lane_id"] 287 pre_geo = self._lanes[pre_lid]["geo"] 288 cur_lid = veh_end["lane_position"]["lane_id"] 289 cur_geo = self._lanes[cur_lid]["geo"] 290 estimate_distance = np.sqrt(2) * cur_geo.distance(pre_geo) 291 eta = max(estimate_distance / SPEED, 5) 292 schedules.append( 293 { 294 "trips": [ 295 { 296 "mode": TRIP_MODE, 297 "end": veh_end, 298 "activity": "other", 299 } 300 ], 301 "departure_time": departure, 302 "loop_count": 1, 303 } 304 ) 305 pre_veh_end = veh_end 306 else: 307 route_len = 0 308 for rid in road_ids: 309 route_len += self._roads[rid]["length"] 310 eta = max(route_len / SPEED, 5) 311 journey = { 312 "type": routingv2.JOURNEY_TYPE_DRIVING, 313 "driving": { 314 "road_ids": road_ids, 315 "eta": eta, 316 }, 317 } 318 schedules.append( 319 { 320 "trips": [ 321 { 322 "mode": TRIP_MODE, 323 "end": veh_end, 324 "activity": "other", 325 "routes": [journey], 326 } 327 ], 328 "departure_time": departure, 329 "loop_count": 1, 330 } 331 ) 332 pre_veh_end = veh_end 333 if stop: 334 duration = stop["duration"] 335 until = stop["until"] 336 if duration: 337 departure += duration 338 elif until: 339 departure = max(departure + eta, until) 340 else: 341 departure += eta 342 return schedules 343 344 def _convert_trips_with_route( 345 self, 346 t: minidom.Element, 347 departure_times: list[np.float64], 348 TRIP_MODE: int, 349 ROAD_LANE_TYPE: Union[Literal["walking_lane_ids"], Literal["driving_lane_ids"]], 350 SPEED: float, 351 trip_id: int, 352 trip_type: Union[Literal["trip"], Literal["flow"], Literal["vehicle"]] = "flow", 353 ): 354 if t.hasAttribute("route"): 355 route_id = t.getAttribute("route") 356 troute = self.route_dict[route_id] 357 else: 358 troute = t.getElementsByTagName("route")[0] 359 for departure in departure_times: 360 edges = troute.getAttribute("edges").split(" ") 361 repeat = ( 362 int(troute.getAttribute("repeat")) 363 if troute.hasAttribute("repeat") 364 else 0 365 ) 366 vstops = troute.getElementsByTagName("stop") 367 rid2stop = self._convert_stops( 368 all_stops=list(t.getElementsByTagName("stop")) + list(vstops), 369 trip_id=trip_id, 370 trip_type=trip_type, 371 ) 372 cycle_time = ( 373 self._convert_time(troute.getAttribute("cycleTime")) 374 if troute.hasAttribute("cycleTime") 375 else np.float64(0) 376 ) 377 route_trips = self._convert_route_trips(edges, repeat, cycle_time, rid2stop) 378 379 if not route_trips: 380 logging.warning(f"Bad route at {trip_type} {trip_id}") 381 continue 382 # processing route_trips 383 self._route_trips_to_person( 384 route_trips, 385 t, 386 trip_id, 387 ROAD_LANE_TYPE, 388 trip_type, 389 TRIP_MODE, 390 SPEED, 391 departure, 392 ) 393 394 def _convert_flows_with_from_to( 395 self, 396 f: minidom.Element, 397 departure_times: list[np.float64], 398 flow_id: int, 399 ROAD_LANE_TYPE: Union[Literal["walking_lane_ids"], Literal["driving_lane_ids"]], 400 TRIP_MODE: int, 401 ): 402 from_eid = f.getAttribute("from") 403 from_rid = self._id2uid[from_eid] 404 from_road = self._roads[from_rid] 405 to_eid = f.getAttribute("to") 406 to_rid = self._id2uid[to_eid] 407 to_road = self._roads[to_rid] 408 for departure in departure_times: 409 flow_home = self._get_trip_position( 410 f, 411 flow_id, 412 from_road, 413 from_rid, 414 ROAD_LANE_TYPE, 415 trip_type="flow", 416 attribute="departLane", 417 ) 418 if not flow_home: 419 break 420 flow_end = self._get_trip_position( 421 f, 422 flow_id, 423 to_road, 424 to_rid, 425 ROAD_LANE_TYPE, 426 trip_type="flow", 427 attribute="arrivalLane", 428 ) 429 if not flow_end: 430 break 431 schedules = [ 432 { 433 "trips": [ 434 { 435 "mode": TRIP_MODE, 436 "end": flow_end, 437 "activity": "other", 438 } 439 ], 440 "departure_time": departure, 441 "loop_count": 1, 442 } 443 ] 444 self._output_agents.append( 445 { 446 "id": self.agent_uid, 447 "home": flow_home, 448 "attribute": self.agent_attribute, 449 "vehicle_attribute": self.vehicle_attribute, 450 "pedestrian_attribute": self.pedestrian_attribute, 451 "bike_attribute": self.bike_attribute, 452 "schedules": schedules, 453 } 454 ) 455 self.agent_uid += 1 456 457 def _convert_stops( 458 self, 459 all_stops: list, 460 trip_id: int, 461 trip_type: Union[Literal["trip"], Literal["flow"], Literal["vehicle"]] = "flow", 462 ): 463 rid2stop = {} 464 for s in all_stops: 465 if any( 466 [ 467 s.hasAttribute(stop_type) 468 for stop_type in [ 469 "containerStop", 470 ] 471 ] 472 ): 473 logging.warning(f"Unsupported stop type at {trip_type} {trip_id}") 474 continue 475 if s.hasAttribute("busStop"): 476 stop_id = s.getAttribute("busStop") 477 if stop_id in self._additional_stops.keys(): 478 (veh_stop, parent_rid) = self._additional_stops[stop_id] 479 else: 480 logging.warning(f"Invalid busStop {stop_id}") 481 continue 482 elif s.hasAttribute("chargingStation"): 483 stop_id = s.getAttribute("chargingStation") 484 if stop_id in self._additional_stops.keys(): 485 (veh_stop, parent_rid) = self._additional_stops[stop_id] 486 else: 487 logging.warning(f"Invalid chargingStation {stop_id}") 488 continue 489 elif s.hasAttribute("parkingArea"): 490 stop_id = s.getAttribute("parkingArea") 491 if stop_id in self._additional_stops.keys(): 492 (veh_stop, parent_rid) = self._additional_stops[stop_id] 493 else: 494 logging.warning(f"Invalid parkingArea {stop_id}") 495 continue 496 elif s.getAttribute("lane") in self._id2uid.keys(): 497 stop_lid = self._id2uid[s.getAttribute("lane")] 498 stop_lane = self._lanes[stop_lid] 499 start_pos = ( 500 np.float64(s.getAttribute("startPos")) 501 if s.hasAttribute("startPos") 502 else 0.1 * stop_lane["length"] 503 ) 504 if start_pos < 0: 505 start_pos += stop_lane["length"] 506 end_pos = ( 507 np.float64(s.getAttribute("endPos")) 508 if s.hasAttribute("endPos") 509 else 0.9 * stop_lane["length"] 510 ) 511 if end_pos < 0: 512 end_pos += stop_lane["length"] 513 stop_s = (end_pos + start_pos) / 2 514 stop_s = np.clip( 515 stop_s, 0.1 * stop_lane["length"], 0.9 * stop_lane["length"] 516 ) 517 veh_stop = { 518 "lane_position": { 519 "lane_id": stop_lid, 520 "s": stop_s, 521 } 522 } 523 parent_rid = stop_lane["parent_id"] 524 else: 525 logging.warning(f"Unsupported stop type at {trip_type} {trip_id}") 526 continue 527 duration = ( 528 self._convert_time(s.getAttribute("duration")) 529 if s.hasAttribute("duration") 530 else None 531 ) 532 until = ( 533 self._convert_time(s.getAttribute("until")) 534 if s.hasAttribute("until") 535 else None 536 ) 537 if not duration and not until: 538 continue 539 else: 540 rid2stop[parent_rid] = { 541 "veh_end": veh_stop, 542 "duration": duration, 543 "until": until, 544 } 545 return rid2stop 546 547 def _get_trip_position( 548 self, 549 t: minidom.Element, 550 trip_id: int, 551 road: dict, 552 road_id: int, 553 ROAD_LANE_TYPE: Union[Literal["walking_lane_ids"], Literal["driving_lane_ids"]], 554 trip_type: Union[Literal["trip"], Literal["flow"], Literal["vehicle"]], 555 attribute: Union[Literal["departLane"], Literal["arrivalLane"]], 556 ): 557 lid = None 558 res_pos = {} 559 if t.hasAttribute(attribute): 560 attribute_id = t.getAttribute(attribute) 561 if attribute_id in self._id2uid.keys(): 562 lid = self._id2uid[attribute_id] 563 if not lid or lid not in road[ROAD_LANE_TYPE]: 564 lid = random.choice(road[ROAD_LANE_TYPE]) 565 if not road[ROAD_LANE_TYPE]: 566 logging.warning( 567 f"Wrong Lane Type {ROAD_LANE_TYPE} at {road_id} at {trip_type} {trip_id}" 568 ) 569 lid = None 570 s_proj = random.uniform(0.1, 0.9) * self._lanes[lid]["length"] 571 if lid is not None: 572 res_pos = { 573 "lane_position": { 574 "lane_id": lid, 575 "s": s_proj, 576 } 577 } 578 return res_pos 579 580 def _process_agent_type(self): 581 agent_type = self.agent_type 582 if agent_type == "AGENT_TYPE_PERSON": 583 TRIP_MODE = tripv2.TRIP_MODE_WALK_ONLY 584 SPEED = random.uniform(0.3, 0.8) * 2 585 ROAD_LANE_TYPE = "walking_lane_ids" 586 elif agent_type == "AGENT_TYPE_BIKE": 587 TRIP_MODE = tripv2.TRIP_MODE_BIKE_WALK 588 SPEED = random.uniform(3, 6) 589 ROAD_LANE_TYPE = "walking_lane_ids" 590 elif agent_type == "AGENT_TYPE_PRIVATE_CAR": 591 TRIP_MODE = tripv2.TRIP_MODE_DRIVE_ONLY 592 SPEED = random.uniform(0.3, 0.8) * 50 / 3.6 593 ROAD_LANE_TYPE = "driving_lane_ids" 594 else: 595 TRIP_MODE = tripv2.TRIP_MODE_DRIVE_ONLY 596 SPEED = random.uniform(0.3, 0.8) * 50 / 3.6 597 ROAD_LANE_TYPE = "driving_lane_ids" 598 return (TRIP_MODE, SPEED, ROAD_LANE_TYPE) 599 600 def _route_trips_to_person( 601 self, 602 route_trips: list, 603 t: minidom.Element, 604 trip_id: int, 605 ROAD_LANE_TYPE: Union[Literal["walking_lane_ids"], Literal["driving_lane_ids"]], 606 trip_type: Union[Literal["trip"], Literal["flow"], Literal["vehicle"]], 607 TRIP_MODE: int, 608 SPEED: float, 609 departure: np.float64, 610 ): 611 home_rid = route_trips[0]["road_ids"][0] 612 for i in range(len(route_trips) - 1): 613 cur_route = route_trips[i] 614 next_route = route_trips[i + 1] 615 if not cur_route["road_ids"][-1] == next_route["road_ids"][0]: 616 assert ( 617 home_rid == next_route["road_ids"][0] 618 ) # only process when `repeat` is valid 619 cur_route["road_ids"].append(home_rid) 620 621 home_road = self._roads[home_rid] 622 veh_home = self._get_trip_position( 623 t, 624 trip_id, 625 home_road, 626 home_rid, 627 ROAD_LANE_TYPE, 628 trip_type, 629 attribute="departLane", 630 ) 631 if not veh_home: 632 return 633 pre_veh_end = veh_home 634 635 schedules = self._process_route_trips( 636 t, 637 route_trips, 638 trip_id, 639 pre_veh_end, 640 TRIP_MODE, 641 ROAD_LANE_TYPE, 642 SPEED, 643 departure, 644 trip_type, 645 ) 646 self._output_agents.append( 647 { 648 "id": self.agent_uid, 649 "home": veh_home, 650 "attribute": self.agent_attribute, 651 "vehicle_attribute": self.vehicle_attribute, 652 "pedestrian_attribute": self.pedestrian_attribute, 653 "bike_attribute": self.bike_attribute, 654 "schedules": schedules, 655 } 656 ) 657 self.agent_uid += 1 658 659 def convert_route(self): 660 self.agent_uid = 0 661 DEFAULT_AGENT_ATTRIBUTE = {} 662 DEFAULT_VEHICLE_ATTRIBUTE = { 663 "length": 5, 664 "width": 2, 665 "max_speed": 41.6666666667, 666 "max_acceleration": 3, 667 "max_braking_acceleration": -10, 668 "usual_acceleration": 2, 669 "usual_braking_acceleration": -4.5, 670 "lane_change_length": 10, 671 "min_gap": 1, 672 } 673 DEFAULT_PEDESTRIAN_ATTRIBUTE = {"speed": 1.34} 674 DEFAULT_BIKE_ATTRIBUTE = {"speed": 5} 675 DEFAULT_AGENT_TYPE = "AGENT_TYPE_PRIVATE_CAR" 676 677 # Route contains the edges that all vehicles pass through, that is, the complete trajectory 678 # Route can be defined separately from vehicle or under vehicle, so additional judgment is required. 679 self.route_dict = {} 680 for r in self._routes: 681 route_id = r.getAttribute("id") 682 self.route_dict[route_id] = r 683 if self._trips: 684 logging.info("Converting trips") 685 for t in self._trips: 686 if t.hasAttribute("type"): 687 trip_type = t.getAttribute("type") 688 ( 689 self.agent_attribute, 690 self.vehicle_attribute, 691 self.pedestrian_attribute, 692 self.bike_attribute, 693 self.agent_type, 694 ) = self._vtype[trip_type] 695 else: 696 ( 697 self.agent_attribute, 698 self.vehicle_attribute, 699 self.pedestrian_attribute, 700 self.bike_attribute, 701 self.agent_type, 702 ) = ( 703 DEFAULT_AGENT_ATTRIBUTE, 704 DEFAULT_VEHICLE_ATTRIBUTE, 705 DEFAULT_PEDESTRIAN_ATTRIBUTE, 706 DEFAULT_BIKE_ATTRIBUTE, 707 DEFAULT_AGENT_TYPE, 708 ) 709 (TRIP_MODE, SPEED, ROAD_LANE_TYPE) = self._process_agent_type() 710 trip_id = t.getAttribute("id") 711 departure = self._convert_time(t.getAttribute("depart")) 712 if not t.hasAttribute("from") or not t.hasAttribute("to"): 713 # no from and to means this item has route 714 if t.hasAttribute("route"): 715 route_id = t.getAttribute("route") 716 troute = self.route_dict[route_id] 717 else: 718 troute = t.getElementsByTagName("route")[0] 719 edges = troute.getAttribute("edges").split(" ") 720 repeat = ( 721 int(troute.getAttribute("repeat")) 722 if troute.hasAttribute("repeat") 723 else 0 724 ) 725 vstops = troute.getElementsByTagName("stop") 726 rid2stop = self._convert_stops( 727 all_stops=list(t.getElementsByTagName("stop")) + list(vstops), 728 trip_id=trip_id, 729 trip_type="trip", 730 ) 731 732 cycle_time = ( 733 self._convert_time(troute.getAttribute("cycleTime")) 734 if troute.hasAttribute("cycleTime") 735 else np.float64(0) 736 ) 737 route_trips = self._convert_route_trips( 738 edges, repeat, cycle_time, rid2stop 739 ) 740 741 if not route_trips: 742 logging.warning(f"Bad route at trip {trip_id}") 743 continue 744 # process route_trips 745 self._route_trips_to_person( 746 route_trips, 747 t, 748 trip_id, 749 ROAD_LANE_TYPE, 750 "trip", 751 TRIP_MODE, 752 SPEED, 753 departure, 754 ) 755 else: 756 from_eid = t.getAttribute("from") 757 via_eids = ( 758 t.getAttribute("via").split(" ") if t.hasAttribute("via") else [] 759 ) 760 to_eid = t.getAttribute("to") 761 from_rid = self._id2uid[from_eid] 762 from_road = self._roads[from_rid] 763 to_rid = self._id2uid[to_eid] 764 to_road = self._roads[to_rid] 765 trip_home = self._get_trip_position( 766 t, 767 trip_id, 768 from_road, 769 from_rid, 770 ROAD_LANE_TYPE, 771 trip_type="trip", 772 attribute="departLane", 773 ) 774 if not trip_home: 775 continue 776 trip_end = self._get_trip_position( 777 t, 778 trip_id, 779 to_road, 780 to_rid, 781 ROAD_LANE_TYPE, 782 trip_type="trip", 783 attribute="arrivalLane", 784 ) 785 if not trip_end: 786 continue 787 via_eids.append(to_eid) 788 via_rids = [] 789 for eid in via_eids: 790 if eid in self._id2uid.keys(): 791 via_rids.append(self._id2uid[eid]) 792 schedules = [] 793 via_ends = [{} for _ in range(len(via_rids))] 794 via_ends[-1] = trip_end 795 pre_via_end = trip_home 796 for i, rid in enumerate(via_rids): 797 via_end = via_ends[i] 798 if not via_end: 799 via_road = self._roads[rid] 800 if not via_road[ROAD_LANE_TYPE]: 801 continue 802 via_lid = random.choice(via_road[ROAD_LANE_TYPE]) 803 via_s = ( 804 random.uniform(0.1, 0.9) * self._lanes[via_lid]["length"] 805 ) 806 via_end = { 807 "lane_position": { 808 "lane_id": via_lid, 809 "s": via_s, 810 } 811 } 812 pre_lid = pre_via_end["lane_position"]["lane_id"] 813 pre_geo = self._lanes[pre_lid]["geo"] 814 cur_lid = via_end["lane_position"]["lane_id"] 815 cur_geo = self._lanes[cur_lid]["geo"] 816 estimate_distance = np.sqrt(2) * cur_geo.distance(pre_geo) 817 eta = max(estimate_distance / SPEED, 5) 818 schedules.append( 819 { 820 "trips": [ 821 { 822 "mode": TRIP_MODE, 823 "end": via_end, 824 "activity": "other", 825 } 826 ], 827 "departure_time": departure, 828 "loop_count": 1, 829 } 830 ) 831 departure += eta 832 pre_via_end = via_end 833 self._output_agents.append( 834 { 835 "id": self.agent_uid, 836 "home": trip_home, 837 "attribute": self.agent_attribute, 838 "vehicle_attribute": self.vehicle_attribute, 839 "pedestrian_attribute": self.pedestrian_attribute, 840 "bike_attribute": self.bike_attribute, 841 "schedules": schedules, 842 } 843 ) 844 self.agent_uid += 1 845 846 def get_flow_departure_times( 847 f: minidom.Element, begin_time: np.float64, end_time: np.float64 848 ) -> list[np.float64]: 849 departure_times = [] 850 if f.hasAttribute("number"): 851 number = int(f.getAttribute("number")) 852 departure_times = list( 853 np.linspace(begin, end, number).astype(np.float64) 854 ) 855 elif f.hasAttribute("period"): 856 period = self._convert_time(f.getAttribute("period")) 857 number = int((end - begin) / period) 858 departure_times = list( 859 np.linspace(begin, end, number).astype(np.float64) 860 ) 861 elif f.hasAttribute("vehsPerHour"): 862 vehs_per_hour = int(f.getAttribute("vehsPerHour")) 863 number = int(vehs_per_hour * (end_time - begin_time) / 3600) 864 departure_times = list( 865 np.linspace(begin, end, number).astype(np.float64) 866 ) 867 elif f.hasAttribute("probability"): 868 prob = np.float64(f.getAttribute("probability")) 869 for i in range(int(end - begin) + 1): 870 if random.random() < prob: 871 departure_times.append(np.float64(i + begin)) 872 return departure_times 873 874 if self._flows or self._intervals: 875 logging.info("Converting flows") 876 for f in self._flows: 877 flow_id = f.getAttribute("id") 878 begin = self._convert_time(f.getAttribute("begin")) 879 end = self._convert_time(f.getAttribute("end")) 880 departure_times = get_flow_departure_times(f, begin, end) 881 if len(departure_times) < 1: 882 logging.warning(f"Incomplete flow {flow_id} at vehicle num!") 883 continue 884 if f.hasAttribute("type"): 885 flow_type = f.getAttribute("type") 886 ( 887 self.agent_attribute, 888 self.vehicle_attribute, 889 self.pedestrian_attribute, 890 self.bike_attribute, 891 self.agent_type, 892 ) = self._vtype[flow_type] 893 else: 894 ( 895 self.agent_attribute, 896 self.vehicle_attribute, 897 self.pedestrian_attribute, 898 self.bike_attribute, 899 self.agent_type, 900 ) = ( 901 DEFAULT_AGENT_ATTRIBUTE, 902 DEFAULT_VEHICLE_ATTRIBUTE, 903 DEFAULT_PEDESTRIAN_ATTRIBUTE, 904 DEFAULT_BIKE_ATTRIBUTE, 905 DEFAULT_AGENT_TYPE, 906 ) 907 (TRIP_MODE, SPEED, ROAD_LANE_TYPE) = self._process_agent_type() 908 if not f.hasAttribute("from") or not f.hasAttribute("to"): 909 # no from and to means this item has route 910 self._convert_trips_with_route( 911 f, 912 departure_times, 913 TRIP_MODE, 914 ROAD_LANE_TYPE, 915 SPEED, 916 trip_id=flow_id, 917 trip_type="flow", 918 ) 919 else: 920 self._convert_flows_with_from_to( 921 f, departure_times, flow_id, ROAD_LANE_TYPE, TRIP_MODE 922 ) 923 for i in self._intervals: 924 begin = self._convert_time(i.getAttribute("begin")) 925 end = self._convert_time(i.getAttribute("end")) 926 for f in i.getElementsByTagName("flow"): 927 flow_id = f.getAttribute("id") 928 departure_times = get_flow_departure_times(f, begin, end) 929 if len(departure_times) < 1: 930 logging.warning(f"Incomplete flow {flow_id} at vehicle num!") 931 continue 932 if f.hasAttribute("type"): 933 flow_type = f.getAttribute("type") 934 ( 935 self.agent_attribute, 936 self.vehicle_attribute, 937 self.pedestrian_attribute, 938 self.bike_attribute, 939 self.agent_type, 940 ) = self._vtype[flow_type] 941 else: 942 ( 943 self.agent_attribute, 944 self.vehicle_attribute, 945 self.pedestrian_attribute, 946 self.bike_attribute, 947 self.agent_type, 948 ) = ( 949 DEFAULT_AGENT_ATTRIBUTE, 950 DEFAULT_VEHICLE_ATTRIBUTE, 951 DEFAULT_PEDESTRIAN_ATTRIBUTE, 952 DEFAULT_BIKE_ATTRIBUTE, 953 DEFAULT_AGENT_TYPE, 954 ) 955 (TRIP_MODE, SPEED, ROAD_LANE_TYPE) = self._process_agent_type() 956 if not f.hasAttribute("from") or not f.hasAttribute("to"): 957 # no from and to means this item has route 958 self._convert_trips_with_route( 959 f, 960 departure_times, 961 TRIP_MODE, 962 ROAD_LANE_TYPE, 963 SPEED, 964 flow_id, 965 trip_type="flow", 966 ) 967 else: 968 self._convert_flows_with_from_to( 969 f, departure_times, flow_id, ROAD_LANE_TYPE, TRIP_MODE 970 ) 971 if self._vehicles: 972 logging.info("Converting routes") 973 for v in self._vehicles: 974 veh_id = v.getAttribute("id") 975 if v.hasAttribute("type"): 976 vehicle_type = v.getAttribute("type") 977 ( 978 self.agent_attribute, 979 self.vehicle_attribute, 980 self.pedestrian_attribute, 981 self.bike_attribute, 982 self.agent_type, 983 ) = self._vtype[vehicle_type] 984 else: 985 ( 986 self.agent_attribute, 987 self.vehicle_attribute, 988 self.pedestrian_attribute, 989 self.bike_attribute, 990 self.agent_type, 991 ) = ( 992 DEFAULT_AGENT_ATTRIBUTE, 993 DEFAULT_VEHICLE_ATTRIBUTE, 994 DEFAULT_PEDESTRIAN_ATTRIBUTE, 995 DEFAULT_BIKE_ATTRIBUTE, 996 DEFAULT_AGENT_TYPE, 997 ) 998 (TRIP_MODE, SPEED, ROAD_LANE_TYPE) = self._process_agent_type() 999 if v.hasAttribute("route"): 1000 route_id = v.getAttribute("route") 1001 vroute = self.route_dict[route_id] 1002 else: 1003 vroute = v.getElementsByTagName("route")[0] 1004 departure = self._convert_time(v.getAttribute("depart")) 1005 edges = vroute.getAttribute("edges").split(" ") 1006 repeat = ( 1007 int(vroute.getAttribute("repeat")) 1008 if vroute.hasAttribute("repeat") 1009 else 0 1010 ) 1011 vstops = vroute.getElementsByTagName("stop") 1012 rid2stop = self._convert_stops( 1013 all_stops=list(vstops), trip_id=veh_id, trip_type="vehicle" 1014 ) 1015 cycle_time = ( 1016 self._convert_time(vroute.getAttribute("cycleTime")) 1017 if vroute.hasAttribute("cycleTime") 1018 else np.float64(0) 1019 ) 1020 route_trips = self._convert_route_trips(edges, repeat, cycle_time, rid2stop) 1021 if not route_trips: 1022 logging.warning(f"Bad route at vehicle {veh_id}") 1023 continue 1024 # process route_trips 1025 self._route_trips_to_person( 1026 route_trips, 1027 v, 1028 veh_id, 1029 ROAD_LANE_TYPE, 1030 "vehicle", 1031 TRIP_MODE, 1032 SPEED, 1033 departure, 1034 ) 1035 1036 return {"persons": self._output_agents}
RouteConverter( converted_map: city.map.v2.map_pb2.Map, sumo_id_mappings: dict, route_path: str, additional_path: Optional[str] = None, seed: Optional[int] = 0)
19 def __init__( 20 self, 21 converted_map: Map, 22 sumo_id_mappings: dict, 23 route_path: str, 24 additional_path: Optional[str] = None, 25 seed: Optional[int] = 0, 26 ): 27 """ 28 Args: 29 - converted_map: The converted map from SUMO network. 30 - sumo_id_mappings: The mapping from SUMO id to the unique id in the converted map. 31 - route_path: The path to the SUMO route file. 32 - additional_path: The path to the additional file containing bus stops, charging stations, and parking areas. 33 - seed: The random seed. 34 """ 35 if seed is not None: 36 random.seed(seed) 37 self._additional_path = additional_path # additional file with "busStop","chargingStation","parkingArea" 38 self._id2uid = sumo_id_mappings 39 m = converted_map 40 logging.info("Reading converted map") 41 self._lanes = {} 42 self._juncs = {} 43 self._roads = {} 44 for l in m.lanes: 45 lid = l.id 46 pres = l.predecessors 47 sucs = l.successors 48 self._lanes[lid] = { 49 "type": l.type, 50 "geo": LineString([[p.x, p.y] for p in l.center_line.nodes]), 51 "in_lids": [p.id for p in pres], 52 "out_lids": [s.id for s in sucs], 53 "parent_id": l.parent_id, 54 "length": l.length, 55 } 56 for j in m.junctions: 57 jid = j.id 58 self._juncs[jid] = { 59 "lane_ids": j.lane_ids, 60 } 61 for r in m.roads: 62 rid = r.id 63 self._roads[rid] = { 64 "lane_ids": r.lane_ids, 65 "length": self._lanes[r.lane_ids[len(r.lane_ids) // 2]]["length"], 66 "driving_lane_ids": [ 67 lid 68 for lid in r.lane_ids 69 if self._lanes[lid]["type"] == mapv2.LANE_TYPE_DRIVING 70 ], 71 "walking_lane_ids": [ 72 lid 73 for lid in r.lane_ids 74 if self._lanes[lid]["type"] == mapv2.LANE_TYPE_WALKING 75 ], 76 } 77 logging.info(f"Reading route from {route_path}") 78 dom_tree = parse(route_path) 79 # get the root node 80 root_node = dom_tree.documentElement 81 # read SUMO .route.xml 82 self._vtype = ( 83 {} 84 ) # vehicle_id -> (agent_attribute,vehicle_attribute,pedestrian_attribute,bike_attribute,agent_type,) 85 self._routes = root_node.getElementsByTagName("route") 86 self._trips = root_node.getElementsByTagName("trip") 87 self._flows = root_node.getElementsByTagName("flow") 88 self._intervals = root_node.getElementsByTagName( 89 "interval" 90 ) # interval contains multiple `flows` 91 self._vehicles = root_node.getElementsByTagName("vehicle") 92 # output data 93 self._output_agents = [] 94 for v in root_node.getElementsByTagName("vType"): 95 vid = v.getAttribute("id") 96 max_acc = ( 97 np.float64(v.getAttribute("accel")) if v.hasAttribute("accel") else 3.0 98 ) 99 max_dec = ( 100 -np.float64(v.getAttribute("decel")) 101 if v.hasAttribute("decel") 102 else -4.5 103 ) 104 length = ( 105 np.float64(v.getAttribute("length")) 106 if v.hasAttribute("length") 107 else 5.0 108 ) 109 max_speed = ( 110 np.float64(v.getAttribute("maxSpeed")) 111 if v.hasAttribute("maxSpeed") 112 else 41.6666666667 113 ) 114 width = ( 115 np.float64(v.getAttribute("width")) if v.hasAttribute("width") else 2.0 116 ) 117 min_gap = ( 118 np.float64(v.getAttribute("minGap")) 119 if v.hasAttribute("minGap") 120 else 1.0 121 ) 122 v_class = v.getAttribute("vClass") if v.hasAttribute("vClass") else "" 123 if v_class == "pedestrian": 124 agent_type = "AGENT_TYPE_PERSON" 125 elif v_class == "bus": 126 agent_type = "AGENT_TYPE_BUS" 127 elif v_class == "bicycle": 128 agent_type = "AGENT_TYPE_BIKE" 129 else: 130 agent_type = "AGENT_TYPE_PRIVATE_CAR" 131 132 usual_acc = 2.0 133 usual_dec = -4.5 134 LC_length = 2 * length 135 # TODO: add other car-following-model 136 # https://sumo.dlr.de/docs/Definition_of_Vehicles%2C_Vehicle_Types%2C_and_Routes.html#car-following_models 137 # model_name = v.getAttribute("carFollowModel") if v.hasAttribute("carFollowModel") else "IDM" 138 self._vtype[vid] = ( 139 {}, 140 { 141 "length": length, 142 "width": width, 143 "max_speed": max_speed, 144 "max_acceleration": max_acc, 145 "max_braking_acceleration": max_dec, 146 "usual_acceleration": usual_acc, 147 "usual_braking_acceleration": usual_dec, 148 "lane_change_length": LC_length, 149 "min_gap": min_gap, 150 }, 151 { 152 "speed": 1.34, 153 }, 154 { 155 "speed": 5.0, 156 }, 157 agent_type, 158 ) 159 self._additional_stops = {} 160 if self._additional_path: 161 add_dom_tree = parse(self._additional_path) 162 add_root_node = add_dom_tree.documentElement 163 for stop_type in ["busStop", "chargingStation", "parkingArea"]: 164 for stop in add_root_node.getElementsByTagName(stop_type): 165 stop_id = stop.getAttribute("id") 166 stop_name = ( 167 stop.getAttribute("name") if stop.hasAttribute("name") else "" 168 ) 169 if stop.getAttribute("lane") in self._id2uid.keys(): 170 stop_lid = self._id2uid[stop.getAttribute("lane")] 171 stop_lane = self._lanes[stop_lid] 172 start_pos = ( 173 np.float64(stop.getAttribute("startPos")) 174 if stop.hasAttribute("startPos") 175 else 0.1 * stop_lane["length"] 176 ) 177 if start_pos < 0: 178 start_pos += stop_lane["length"] 179 end_pos = ( 180 np.float64(stop.getAttribute("endPos")) 181 if stop.hasAttribute("endPos") 182 else 0.9 * stop_lane["length"] 183 ) 184 if end_pos < 0: 185 end_pos += stop_lane["length"] 186 stop_s = (end_pos + start_pos) / 2 187 stop_s = np.clip( 188 stop_s, 0.1 * stop_lane["length"], 0.9 * stop_lane["length"] 189 ) 190 veh_stop = { 191 "lane_position": { 192 "lane_id": stop_lid, 193 "s": stop_s, 194 } 195 } 196 parent_rid = stop_lane["parent_id"] 197 self._additional_stops[stop_id] = (veh_stop, parent_rid) 198 else: 199 logging.warning(f"Invalid stop {stop_id} {stop_name}!")
Args:
- converted_map: The converted map from SUMO network.
- sumo_id_mappings: The mapping from SUMO id to the unique id in the converted map.
- route_path: The path to the SUMO route file.
- additional_path: The path to the additional file containing bus stops, charging stations, and parking areas.
- seed: The random seed.
def
convert_route(self):
659 def convert_route(self): 660 self.agent_uid = 0 661 DEFAULT_AGENT_ATTRIBUTE = {} 662 DEFAULT_VEHICLE_ATTRIBUTE = { 663 "length": 5, 664 "width": 2, 665 "max_speed": 41.6666666667, 666 "max_acceleration": 3, 667 "max_braking_acceleration": -10, 668 "usual_acceleration": 2, 669 "usual_braking_acceleration": -4.5, 670 "lane_change_length": 10, 671 "min_gap": 1, 672 } 673 DEFAULT_PEDESTRIAN_ATTRIBUTE = {"speed": 1.34} 674 DEFAULT_BIKE_ATTRIBUTE = {"speed": 5} 675 DEFAULT_AGENT_TYPE = "AGENT_TYPE_PRIVATE_CAR" 676 677 # Route contains the edges that all vehicles pass through, that is, the complete trajectory 678 # Route can be defined separately from vehicle or under vehicle, so additional judgment is required. 679 self.route_dict = {} 680 for r in self._routes: 681 route_id = r.getAttribute("id") 682 self.route_dict[route_id] = r 683 if self._trips: 684 logging.info("Converting trips") 685 for t in self._trips: 686 if t.hasAttribute("type"): 687 trip_type = t.getAttribute("type") 688 ( 689 self.agent_attribute, 690 self.vehicle_attribute, 691 self.pedestrian_attribute, 692 self.bike_attribute, 693 self.agent_type, 694 ) = self._vtype[trip_type] 695 else: 696 ( 697 self.agent_attribute, 698 self.vehicle_attribute, 699 self.pedestrian_attribute, 700 self.bike_attribute, 701 self.agent_type, 702 ) = ( 703 DEFAULT_AGENT_ATTRIBUTE, 704 DEFAULT_VEHICLE_ATTRIBUTE, 705 DEFAULT_PEDESTRIAN_ATTRIBUTE, 706 DEFAULT_BIKE_ATTRIBUTE, 707 DEFAULT_AGENT_TYPE, 708 ) 709 (TRIP_MODE, SPEED, ROAD_LANE_TYPE) = self._process_agent_type() 710 trip_id = t.getAttribute("id") 711 departure = self._convert_time(t.getAttribute("depart")) 712 if not t.hasAttribute("from") or not t.hasAttribute("to"): 713 # no from and to means this item has route 714 if t.hasAttribute("route"): 715 route_id = t.getAttribute("route") 716 troute = self.route_dict[route_id] 717 else: 718 troute = t.getElementsByTagName("route")[0] 719 edges = troute.getAttribute("edges").split(" ") 720 repeat = ( 721 int(troute.getAttribute("repeat")) 722 if troute.hasAttribute("repeat") 723 else 0 724 ) 725 vstops = troute.getElementsByTagName("stop") 726 rid2stop = self._convert_stops( 727 all_stops=list(t.getElementsByTagName("stop")) + list(vstops), 728 trip_id=trip_id, 729 trip_type="trip", 730 ) 731 732 cycle_time = ( 733 self._convert_time(troute.getAttribute("cycleTime")) 734 if troute.hasAttribute("cycleTime") 735 else np.float64(0) 736 ) 737 route_trips = self._convert_route_trips( 738 edges, repeat, cycle_time, rid2stop 739 ) 740 741 if not route_trips: 742 logging.warning(f"Bad route at trip {trip_id}") 743 continue 744 # process route_trips 745 self._route_trips_to_person( 746 route_trips, 747 t, 748 trip_id, 749 ROAD_LANE_TYPE, 750 "trip", 751 TRIP_MODE, 752 SPEED, 753 departure, 754 ) 755 else: 756 from_eid = t.getAttribute("from") 757 via_eids = ( 758 t.getAttribute("via").split(" ") if t.hasAttribute("via") else [] 759 ) 760 to_eid = t.getAttribute("to") 761 from_rid = self._id2uid[from_eid] 762 from_road = self._roads[from_rid] 763 to_rid = self._id2uid[to_eid] 764 to_road = self._roads[to_rid] 765 trip_home = self._get_trip_position( 766 t, 767 trip_id, 768 from_road, 769 from_rid, 770 ROAD_LANE_TYPE, 771 trip_type="trip", 772 attribute="departLane", 773 ) 774 if not trip_home: 775 continue 776 trip_end = self._get_trip_position( 777 t, 778 trip_id, 779 to_road, 780 to_rid, 781 ROAD_LANE_TYPE, 782 trip_type="trip", 783 attribute="arrivalLane", 784 ) 785 if not trip_end: 786 continue 787 via_eids.append(to_eid) 788 via_rids = [] 789 for eid in via_eids: 790 if eid in self._id2uid.keys(): 791 via_rids.append(self._id2uid[eid]) 792 schedules = [] 793 via_ends = [{} for _ in range(len(via_rids))] 794 via_ends[-1] = trip_end 795 pre_via_end = trip_home 796 for i, rid in enumerate(via_rids): 797 via_end = via_ends[i] 798 if not via_end: 799 via_road = self._roads[rid] 800 if not via_road[ROAD_LANE_TYPE]: 801 continue 802 via_lid = random.choice(via_road[ROAD_LANE_TYPE]) 803 via_s = ( 804 random.uniform(0.1, 0.9) * self._lanes[via_lid]["length"] 805 ) 806 via_end = { 807 "lane_position": { 808 "lane_id": via_lid, 809 "s": via_s, 810 } 811 } 812 pre_lid = pre_via_end["lane_position"]["lane_id"] 813 pre_geo = self._lanes[pre_lid]["geo"] 814 cur_lid = via_end["lane_position"]["lane_id"] 815 cur_geo = self._lanes[cur_lid]["geo"] 816 estimate_distance = np.sqrt(2) * cur_geo.distance(pre_geo) 817 eta = max(estimate_distance / SPEED, 5) 818 schedules.append( 819 { 820 "trips": [ 821 { 822 "mode": TRIP_MODE, 823 "end": via_end, 824 "activity": "other", 825 } 826 ], 827 "departure_time": departure, 828 "loop_count": 1, 829 } 830 ) 831 departure += eta 832 pre_via_end = via_end 833 self._output_agents.append( 834 { 835 "id": self.agent_uid, 836 "home": trip_home, 837 "attribute": self.agent_attribute, 838 "vehicle_attribute": self.vehicle_attribute, 839 "pedestrian_attribute": self.pedestrian_attribute, 840 "bike_attribute": self.bike_attribute, 841 "schedules": schedules, 842 } 843 ) 844 self.agent_uid += 1 845 846 def get_flow_departure_times( 847 f: minidom.Element, begin_time: np.float64, end_time: np.float64 848 ) -> list[np.float64]: 849 departure_times = [] 850 if f.hasAttribute("number"): 851 number = int(f.getAttribute("number")) 852 departure_times = list( 853 np.linspace(begin, end, number).astype(np.float64) 854 ) 855 elif f.hasAttribute("period"): 856 period = self._convert_time(f.getAttribute("period")) 857 number = int((end - begin) / period) 858 departure_times = list( 859 np.linspace(begin, end, number).astype(np.float64) 860 ) 861 elif f.hasAttribute("vehsPerHour"): 862 vehs_per_hour = int(f.getAttribute("vehsPerHour")) 863 number = int(vehs_per_hour * (end_time - begin_time) / 3600) 864 departure_times = list( 865 np.linspace(begin, end, number).astype(np.float64) 866 ) 867 elif f.hasAttribute("probability"): 868 prob = np.float64(f.getAttribute("probability")) 869 for i in range(int(end - begin) + 1): 870 if random.random() < prob: 871 departure_times.append(np.float64(i + begin)) 872 return departure_times 873 874 if self._flows or self._intervals: 875 logging.info("Converting flows") 876 for f in self._flows: 877 flow_id = f.getAttribute("id") 878 begin = self._convert_time(f.getAttribute("begin")) 879 end = self._convert_time(f.getAttribute("end")) 880 departure_times = get_flow_departure_times(f, begin, end) 881 if len(departure_times) < 1: 882 logging.warning(f"Incomplete flow {flow_id} at vehicle num!") 883 continue 884 if f.hasAttribute("type"): 885 flow_type = f.getAttribute("type") 886 ( 887 self.agent_attribute, 888 self.vehicle_attribute, 889 self.pedestrian_attribute, 890 self.bike_attribute, 891 self.agent_type, 892 ) = self._vtype[flow_type] 893 else: 894 ( 895 self.agent_attribute, 896 self.vehicle_attribute, 897 self.pedestrian_attribute, 898 self.bike_attribute, 899 self.agent_type, 900 ) = ( 901 DEFAULT_AGENT_ATTRIBUTE, 902 DEFAULT_VEHICLE_ATTRIBUTE, 903 DEFAULT_PEDESTRIAN_ATTRIBUTE, 904 DEFAULT_BIKE_ATTRIBUTE, 905 DEFAULT_AGENT_TYPE, 906 ) 907 (TRIP_MODE, SPEED, ROAD_LANE_TYPE) = self._process_agent_type() 908 if not f.hasAttribute("from") or not f.hasAttribute("to"): 909 # no from and to means this item has route 910 self._convert_trips_with_route( 911 f, 912 departure_times, 913 TRIP_MODE, 914 ROAD_LANE_TYPE, 915 SPEED, 916 trip_id=flow_id, 917 trip_type="flow", 918 ) 919 else: 920 self._convert_flows_with_from_to( 921 f, departure_times, flow_id, ROAD_LANE_TYPE, TRIP_MODE 922 ) 923 for i in self._intervals: 924 begin = self._convert_time(i.getAttribute("begin")) 925 end = self._convert_time(i.getAttribute("end")) 926 for f in i.getElementsByTagName("flow"): 927 flow_id = f.getAttribute("id") 928 departure_times = get_flow_departure_times(f, begin, end) 929 if len(departure_times) < 1: 930 logging.warning(f"Incomplete flow {flow_id} at vehicle num!") 931 continue 932 if f.hasAttribute("type"): 933 flow_type = f.getAttribute("type") 934 ( 935 self.agent_attribute, 936 self.vehicle_attribute, 937 self.pedestrian_attribute, 938 self.bike_attribute, 939 self.agent_type, 940 ) = self._vtype[flow_type] 941 else: 942 ( 943 self.agent_attribute, 944 self.vehicle_attribute, 945 self.pedestrian_attribute, 946 self.bike_attribute, 947 self.agent_type, 948 ) = ( 949 DEFAULT_AGENT_ATTRIBUTE, 950 DEFAULT_VEHICLE_ATTRIBUTE, 951 DEFAULT_PEDESTRIAN_ATTRIBUTE, 952 DEFAULT_BIKE_ATTRIBUTE, 953 DEFAULT_AGENT_TYPE, 954 ) 955 (TRIP_MODE, SPEED, ROAD_LANE_TYPE) = self._process_agent_type() 956 if not f.hasAttribute("from") or not f.hasAttribute("to"): 957 # no from and to means this item has route 958 self._convert_trips_with_route( 959 f, 960 departure_times, 961 TRIP_MODE, 962 ROAD_LANE_TYPE, 963 SPEED, 964 flow_id, 965 trip_type="flow", 966 ) 967 else: 968 self._convert_flows_with_from_to( 969 f, departure_times, flow_id, ROAD_LANE_TYPE, TRIP_MODE 970 ) 971 if self._vehicles: 972 logging.info("Converting routes") 973 for v in self._vehicles: 974 veh_id = v.getAttribute("id") 975 if v.hasAttribute("type"): 976 vehicle_type = v.getAttribute("type") 977 ( 978 self.agent_attribute, 979 self.vehicle_attribute, 980 self.pedestrian_attribute, 981 self.bike_attribute, 982 self.agent_type, 983 ) = self._vtype[vehicle_type] 984 else: 985 ( 986 self.agent_attribute, 987 self.vehicle_attribute, 988 self.pedestrian_attribute, 989 self.bike_attribute, 990 self.agent_type, 991 ) = ( 992 DEFAULT_AGENT_ATTRIBUTE, 993 DEFAULT_VEHICLE_ATTRIBUTE, 994 DEFAULT_PEDESTRIAN_ATTRIBUTE, 995 DEFAULT_BIKE_ATTRIBUTE, 996 DEFAULT_AGENT_TYPE, 997 ) 998 (TRIP_MODE, SPEED, ROAD_LANE_TYPE) = self._process_agent_type() 999 if v.hasAttribute("route"): 1000 route_id = v.getAttribute("route") 1001 vroute = self.route_dict[route_id] 1002 else: 1003 vroute = v.getElementsByTagName("route")[0] 1004 departure = self._convert_time(v.getAttribute("depart")) 1005 edges = vroute.getAttribute("edges").split(" ") 1006 repeat = ( 1007 int(vroute.getAttribute("repeat")) 1008 if vroute.hasAttribute("repeat") 1009 else 0 1010 ) 1011 vstops = vroute.getElementsByTagName("stop") 1012 rid2stop = self._convert_stops( 1013 all_stops=list(vstops), trip_id=veh_id, trip_type="vehicle" 1014 ) 1015 cycle_time = ( 1016 self._convert_time(vroute.getAttribute("cycleTime")) 1017 if vroute.hasAttribute("cycleTime") 1018 else np.float64(0) 1019 ) 1020 route_trips = self._convert_route_trips(edges, repeat, cycle_time, rid2stop) 1021 if not route_trips: 1022 logging.warning(f"Bad route at vehicle {veh_id}") 1023 continue 1024 # process route_trips 1025 self._route_trips_to_person( 1026 route_trips, 1027 v, 1028 veh_id, 1029 ROAD_LANE_TYPE, 1030 "vehicle", 1031 TRIP_MODE, 1032 SPEED, 1033 departure, 1034 ) 1035 1036 return {"persons": self._output_agents}