1# -*- coding: utf-8 -*- 2# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo 3# Copyright (C) 2011-2019 German Aerospace Center (DLR) and others. 4# This program and the accompanying materials 5# are made available under the terms of the Eclipse Public License v2.0 6# which accompanies this distribution, and is available at 7# http://www.eclipse.org/legal/epl-v20.html 8# SPDX-License-Identifier: EPL-2.0 9 10# @file _simulation.py 11# @author Daniel Krajzewicz 12# @author Jakob Erdmann 13# @author Michael Behrisch 14# @date 2011-03-15 15# @version $Id$ 16 17from __future__ import absolute_import 18import struct 19import collections 20import warnings 21from . import constants as tc 22from .domain import Domain 23from .storage import Storage 24 25Stage = collections.namedtuple('Stage', ['stageType', 'vType', 'line', 'destStop', 'edges', 'travelTime', 'cost', 26 'length', 'intended', 'depart', 'departPos', 'arrivalPos', 'description']) 27 28 29def _readStage(result): 30 # compound size and type 31 assert(result.read("!i")[0] == 13) 32 stageType = result.readTypedInt() 33 vType = result.readTypedString() 34 line = result.readTypedString() 35 destStop = result.readTypedString() 36 edges = result.readTypedStringList() 37 travelTime = result.readTypedDouble() 38 cost = result.readTypedDouble() 39 length = result.readTypedDouble() 40 intended = result.readTypedString() 41 depart = result.readTypedDouble() 42 departPos = result.readTypedDouble() 43 arrivalPos = result.readTypedDouble() 44 description = result.readTypedString() 45 return Stage(stageType, vType, line, destStop, edges, travelTime, cost, 46 length, intended, depart, departPos, arrivalPos, description) 47 48 49_RETURN_VALUE_FUNC = {tc.VAR_TIME: Storage.readDouble, 50 tc.VAR_TIME_STEP: Storage.readInt, 51 tc.VAR_LOADED_VEHICLES_NUMBER: Storage.readInt, 52 tc.VAR_LOADED_VEHICLES_IDS: Storage.readStringList, 53 tc.VAR_DEPARTED_VEHICLES_NUMBER: Storage.readInt, 54 tc.VAR_DEPARTED_VEHICLES_IDS: Storage.readStringList, 55 tc.VAR_ARRIVED_VEHICLES_NUMBER: Storage.readInt, 56 tc.VAR_ARRIVED_VEHICLES_IDS: Storage.readStringList, 57 tc.VAR_PARKING_STARTING_VEHICLES_NUMBER: Storage.readInt, 58 tc.VAR_PARKING_STARTING_VEHICLES_IDS: Storage.readStringList, 59 tc.VAR_PARKING_ENDING_VEHICLES_NUMBER: Storage.readInt, 60 tc.VAR_PARKING_ENDING_VEHICLES_IDS: Storage.readStringList, 61 tc.VAR_STOP_STARTING_VEHICLES_NUMBER: Storage.readInt, 62 tc.VAR_STOP_STARTING_VEHICLES_IDS: Storage.readStringList, 63 tc.VAR_STOP_ENDING_VEHICLES_NUMBER: Storage.readInt, 64 tc.VAR_STOP_ENDING_VEHICLES_IDS: Storage.readStringList, 65 tc.VAR_COLLIDING_VEHICLES_NUMBER: Storage.readInt, 66 tc.VAR_COLLIDING_VEHICLES_IDS: Storage.readStringList, 67 tc.VAR_EMERGENCYSTOPPING_VEHICLES_NUMBER: Storage.readInt, 68 tc.VAR_EMERGENCYSTOPPING_VEHICLES_IDS: Storage.readStringList, 69 tc.VAR_MIN_EXPECTED_VEHICLES: Storage.readInt, 70 tc.VAR_BUS_STOP_WAITING: Storage.readInt, 71 tc.VAR_TELEPORT_STARTING_VEHICLES_NUMBER: Storage.readInt, 72 tc.VAR_TELEPORT_STARTING_VEHICLES_IDS: Storage.readStringList, 73 tc.VAR_TELEPORT_ENDING_VEHICLES_NUMBER: Storage.readInt, 74 tc.VAR_TELEPORT_ENDING_VEHICLES_IDS: Storage.readStringList, 75 tc.VAR_DELTA_T: Storage.readDouble, 76 tc.VAR_NET_BOUNDING_BOX: Storage.readShape} 77 78 79class SimulationDomain(Domain): 80 81 def __init__(self): 82 Domain.__init__(self, "simulation", tc.CMD_GET_SIM_VARIABLE, tc.CMD_SET_SIM_VARIABLE, 83 tc.CMD_SUBSCRIBE_SIM_VARIABLE, tc.RESPONSE_SUBSCRIBE_SIM_VARIABLE, 84 tc.CMD_SUBSCRIBE_SIM_CONTEXT, tc.RESPONSE_SUBSCRIBE_SIM_CONTEXT, 85 _RETURN_VALUE_FUNC) 86 87 def getTime(self): 88 """getTime() -> double 89 90 Returns the current simulation time in s. 91 """ 92 return self._getUniversal(tc.VAR_TIME) 93 94 def step(self, time=0.): 95 """step(double) -> None 96 Make a simulation step and simulate up to the given sim time (in seconds). 97 If the given value is 0 or absent, exactly one step is performed. 98 Values smaller than or equal to the current sim time result in no action. 99 """ 100 return self._connection.simulationStep(time) 101 102 def getCurrentTime(self): 103 """getCurrentTime() -> integer 104 105 Returns the current simulation time in ms. 106 """ 107 # we should raise the awareness by removing the DeprecationWarning category below after 1.0 108 warnings.warn("getCurrentTime is deprecated, please use getTime which returns floating point seconds", 109 DeprecationWarning, stacklevel=2) 110 return self._getUniversal(tc.VAR_TIME_STEP) 111 112 def getLoadedNumber(self): 113 """getLoadedNumber() -> integer 114 115 Returns the number of vehicles which were loaded in this time step. 116 """ 117 return self._getUniversal(tc.VAR_LOADED_VEHICLES_NUMBER) 118 119 def getLoadedIDList(self): 120 """getLoadedIDList() -> list(string) 121 122 Returns a list of ids of vehicles which were loaded in this time step. 123 """ 124 return self._getUniversal(tc.VAR_LOADED_VEHICLES_IDS) 125 126 def getDepartedNumber(self): 127 """getDepartedNumber() -> integer 128 129 Returns the number of vehicles which departed (were inserted into the road network) in this time step. 130 """ 131 return self._getUniversal(tc.VAR_DEPARTED_VEHICLES_NUMBER) 132 133 def getDepartedIDList(self): 134 """getDepartedIDList() -> list(string) 135 136 Returns a list of ids of vehicles which departed (were inserted into the road network) in this time step. 137 """ 138 return self._getUniversal(tc.VAR_DEPARTED_VEHICLES_IDS) 139 140 def getArrivedNumber(self): 141 """getArrivedNumber() -> integer 142 143 Returns the number of vehicles which arrived (have reached their destination and are removed from the road 144 network) in this time step. 145 """ 146 return self._getUniversal(tc.VAR_ARRIVED_VEHICLES_NUMBER) 147 148 def getArrivedIDList(self): 149 """getArrivedIDList() -> list(string) 150 151 Returns a list of ids of vehicles which arrived (have reached their destination and are removed from the road 152 network) in this time step. 153 """ 154 return self._getUniversal(tc.VAR_ARRIVED_VEHICLES_IDS) 155 156 def getParkingStartingVehiclesNumber(self): 157 """getParkingStartingVehiclesNumber() -> integer 158 159 . 160 """ 161 return self._getUniversal(tc.VAR_PARKING_STARTING_VEHICLES_NUMBER) 162 163 def getParkingStartingVehiclesIDList(self): 164 """getParkingStartingVehiclesIDList() -> list(string) 165 166 . 167 """ 168 return self._getUniversal(tc.VAR_PARKING_STARTING_VEHICLES_IDS) 169 170 def getParkingEndingVehiclesNumber(self): 171 """getParkingEndingVehiclesNumber() -> integer 172 173 . 174 """ 175 return self._getUniversal(tc.VAR_PARKING_ENDING_VEHICLES_NUMBER) 176 177 def getParkingEndingVehiclesIDList(self): 178 """getParkingEndingVehiclesIDList() -> list(string) 179 180 . 181 """ 182 return self._getUniversal(tc.VAR_PARKING_ENDING_VEHICLES_IDS) 183 184 def getStopStartingVehiclesNumber(self): 185 """getStopStartingVehiclesNumber() -> integer 186 187 . 188 """ 189 return self._getUniversal(tc.VAR_STOP_STARTING_VEHICLES_NUMBER) 190 191 def getStopStartingVehiclesIDList(self): 192 """getStopStartingVehiclesIDList() -> list(string) 193 194 . 195 """ 196 return self._getUniversal(tc.VAR_STOP_STARTING_VEHICLES_IDS) 197 198 def getStopEndingVehiclesNumber(self): 199 """getStopEndingVehiclesNumber() -> integer 200 201 . 202 """ 203 return self._getUniversal(tc.VAR_STOP_ENDING_VEHICLES_NUMBER) 204 205 def getStopEndingVehiclesIDList(self): 206 """getStopEndingVehiclesIDList() -> list(string) 207 208 . 209 """ 210 return self._getUniversal(tc.VAR_STOP_ENDING_VEHICLES_IDS) 211 212 def getCollidingVehiclesNumber(self): 213 """getCollidingVehiclesNumber() -> integer 214 Return number of vehicles involved in a collision (typically 2 per 215 collision). 216 """ 217 return self._getUniversal(tc.VAR_COLLIDING_VEHICLES_NUMBER) 218 219 def getCollidingVehiclesIDList(self): 220 """getCollidingVehiclesIDList() -> list(string) 221 Return Ids of vehicles involved in a collision (typically 2 per 222 collision). 223 """ 224 return self._getUniversal(tc.VAR_COLLIDING_VEHICLES_IDS) 225 226 def getEmergencyStoppingVehiclesNumber(self): 227 """getEmergencyStoppingVehiclesNumber() -> integer 228 Return number of vehicles that performed an emergency stop in the last step 229 """ 230 return self._getUniversal(tc.VAR_EMERGENCYSTOPPING_VEHICLES_NUMBER) 231 232 def getEmergencyStoppingVehiclesIDList(self): 233 """getEmergencyStoppingVehiclesIDList() -> list(string) 234 Return Ids of vehicles that peformed an emergency stop in the last step 235 """ 236 return self._getUniversal(tc.VAR_EMERGENCYSTOPPING_VEHICLES_IDS) 237 238 def getMinExpectedNumber(self): 239 """getMinExpectedNumber() -> integer 240 241 Returns the number of vehicles which are in the net plus the 242 ones still waiting to start. This number may be smaller than 243 the actual number of vehicles still to come because of delayed 244 route file parsing. If the number is 0 however, it is 245 guaranteed that all route files have been parsed completely 246 and all vehicles have left the network. 247 """ 248 return self._getUniversal(tc.VAR_MIN_EXPECTED_VEHICLES) 249 250 def getBusStopWaiting(self, stopID): 251 """getBusStopWaiting() -> integer 252 Get the total number of waiting persons at the named bus stop. 253 """ 254 return self._getUniversal(tc.VAR_BUS_STOP_WAITING, stopID) 255 256 def getStartingTeleportNumber(self): 257 """getStartingTeleportNumber() -> integer 258 259 Returns the number of vehicles which started to teleport in this time step. 260 """ 261 return self._getUniversal(tc.VAR_TELEPORT_STARTING_VEHICLES_NUMBER) 262 263 def getStartingTeleportIDList(self): 264 """getStartingTeleportIDList() -> list(string) 265 266 Returns a list of ids of vehicles which started to teleport in this time step. 267 """ 268 return self._getUniversal(tc.VAR_TELEPORT_STARTING_VEHICLES_IDS) 269 270 def getEndingTeleportNumber(self): 271 """getEndingTeleportNumber() -> integer 272 273 Returns the number of vehicles which ended to be teleported in this time step. 274 """ 275 return self._getUniversal(tc.VAR_TELEPORT_ENDING_VEHICLES_NUMBER) 276 277 def getEndingTeleportIDList(self): 278 """getEndingTeleportIDList() -> list(string) 279 280 Returns a list of ids of vehicles which ended to be teleported in this time step. 281 """ 282 return self._getUniversal(tc.VAR_TELEPORT_ENDING_VEHICLES_IDS) 283 284 def getDeltaT(self): 285 """getDeltaT() -> double 286 Returns the length of one simulation step in seconds 287 """ 288 return self._getUniversal(tc.VAR_DELTA_T) 289 290 def getNetBoundary(self): 291 """getNetBoundary() -> ((double, double), (double, double)) 292 293 The boundary box of the simulation network. 294 """ 295 return self._getUniversal(tc.VAR_NET_BOUNDING_BOX) 296 297 def convert2D(self, edgeID, pos, laneIndex=0, toGeo=False): 298 posType = tc.POSITION_2D 299 if toGeo: 300 posType = tc.POSITION_LON_LAT 301 self._connection._beginMessage(tc.CMD_GET_SIM_VARIABLE, tc.POSITION_CONVERSION, 302 "", 1 + 4 + 1 + 4 + len(edgeID) + 8 + 1 + 1 + 1) 303 self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 2) 304 self._connection._packString(edgeID, tc.POSITION_ROADMAP) 305 self._connection._string += struct.pack("!dBBB", 306 pos, laneIndex, tc.TYPE_UBYTE, posType) 307 return self._connection._checkResult(tc.CMD_GET_SIM_VARIABLE, tc.POSITION_CONVERSION, "").read("!dd") 308 309 def convert3D(self, edgeID, pos, laneIndex=0, toGeo=False): 310 posType = tc.POSITION_3D 311 if toGeo: 312 posType = tc.POSITION_LON_LAT_ALT 313 self._connection._beginMessage(tc.CMD_GET_SIM_VARIABLE, tc.POSITION_CONVERSION, 314 "", 1 + 4 + 1 + 4 + len(edgeID) + 8 + 1 + 1 + 1) 315 self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 2) 316 self._connection._packString(edgeID, tc.POSITION_ROADMAP) 317 self._connection._string += struct.pack("!dBBB", 318 pos, laneIndex, tc.TYPE_UBYTE, posType) 319 return self._connection._checkResult(tc.CMD_GET_SIM_VARIABLE, tc.POSITION_CONVERSION, "").read("!ddd") 320 321 def convertRoad(self, x, y, isGeo=False, vClass="ignoring"): 322 posType = tc.POSITION_2D 323 if isGeo: 324 posType = tc.POSITION_LON_LAT 325 self._connection._beginMessage( 326 tc.CMD_GET_SIM_VARIABLE, tc.POSITION_CONVERSION, "", 1 + 4 + 1 + 8 + 8 + 1 + 1 + 1 + 4 + len(vClass)) 327 self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 3) 328 self._connection._string += struct.pack("!Bdd", posType, x, y) 329 self._connection._string += struct.pack("!BB", tc.TYPE_UBYTE, tc.POSITION_ROADMAP) 330 self._connection._packString(vClass) 331 result = self._connection._checkResult( 332 tc.CMD_GET_SIM_VARIABLE, tc.POSITION_CONVERSION, "") 333 return result.readString(), result.readDouble(), result.read("!B")[0] 334 335 def convertGeo(self, x, y, fromGeo=False): 336 fromType = tc.POSITION_2D 337 toType = tc.POSITION_LON_LAT 338 if fromGeo: 339 fromType = tc.POSITION_LON_LAT 340 toType = tc.POSITION_2D 341 self._connection._beginMessage( 342 tc.CMD_GET_SIM_VARIABLE, tc.POSITION_CONVERSION, "", 1 + 4 + 1 + 8 + 8 + 1 + 1) 343 self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 2) 344 self._connection._string += struct.pack("!Bdd", fromType, x, y) 345 self._connection._string += struct.pack("!BB", tc.TYPE_UBYTE, toType) 346 return self._connection._checkResult(tc.CMD_GET_SIM_VARIABLE, tc.POSITION_CONVERSION, "").read("!dd") 347 348 def getDistance2D(self, x1, y1, x2, y2, isGeo=False, isDriving=False): 349 """getDistance2D(double, double, double, double, boolean, boolean) -> double 350 351 Returns the distance between the two coordinate pairs (x1,y1) and (x2,y2) 352 353 If isGeo=True, coordinates are interpreted as longitude and latitude rather 354 than cartesian coordinates in meters. 355 356 If isDriving=True, the coordinates are mapped onto the road network and the 357 length of the shortest route in the network is returned. Otherwise, the 358 straight-line distance is returned. 359 """ 360 posType = tc.POSITION_2D 361 if isGeo: 362 posType = tc.POSITION_LON_LAT 363 distType = tc.REQUEST_AIRDIST 364 if isDriving: 365 distType = tc.REQUEST_DRIVINGDIST 366 self._connection._beginMessage( 367 tc.CMD_GET_SIM_VARIABLE, tc.DISTANCE_REQUEST, "", 1 + 4 + 1 + 8 + 8 + 1 + 8 + 8 + 1) 368 self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 3) 369 self._connection._string += struct.pack("!Bdd", posType, x1, y1) 370 self._connection._string += struct.pack( 371 "!BddB", posType, x2, y2, distType) 372 return self._connection._checkResult(tc.CMD_GET_SIM_VARIABLE, tc.DISTANCE_REQUEST, "").readDouble() 373 374 def getDistanceRoad(self, edgeID1, pos1, edgeID2, pos2, isDriving=False): 375 """getDistanceRoad(string, double, string, double, boolean) -> double 376 377 Reads two positions on the road network and an indicator whether the air or the driving distance shall be 378 computed. Returns the according distance. 379 """ 380 distType = tc.REQUEST_AIRDIST 381 if isDriving: 382 distType = tc.REQUEST_DRIVINGDIST 383 self._connection._beginMessage(tc.CMD_GET_SIM_VARIABLE, tc.DISTANCE_REQUEST, "", 384 1 + 4 + 1 + 4 + len(edgeID1) + 8 + 1 + 1 + 4 + len(edgeID2) + 8 + 1 + 1) 385 self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 3) 386 self._connection._packString(edgeID1, tc.POSITION_ROADMAP) 387 self._connection._string += struct.pack("!dB", pos1, 0) 388 self._connection._packString(edgeID2, tc.POSITION_ROADMAP) 389 self._connection._string += struct.pack("!dBB", pos2, 0, distType) 390 return self._connection._checkResult(tc.CMD_GET_SIM_VARIABLE, tc.DISTANCE_REQUEST, "").readDouble() 391 392 def findRoute(self, fromEdge, toEdge, vType="", depart=-1., routingMode=0): 393 self._connection._beginMessage(tc.CMD_GET_SIM_VARIABLE, tc.FIND_ROUTE, "", 394 (1 + 4 + 1 + 4 + len(fromEdge) + 1 + 4 + len(toEdge) + 1 + 4 + len(vType) + 395 1 + 8 + 1 + 4)) 396 self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 5) 397 self._connection._packString(fromEdge) 398 self._connection._packString(toEdge) 399 self._connection._packString(vType) 400 self._connection._string += struct.pack("!BdBi", tc.TYPE_DOUBLE, depart, tc.TYPE_INTEGER, routingMode) 401 return _readStage(self._connection._checkResult(tc.CMD_GET_SIM_VARIABLE, tc.FIND_ROUTE, "")) 402 403 def findIntermodalRoute(self, fromEdge, toEdge, modes="", depart=-1., routingMode=0, speed=-1., 404 walkFactor=-1., departPos=0., arrivalPos=tc.INVALID_DOUBLE_VALUE, departPosLat=0., 405 pType="", vType="", destStop=""): 406 self._connection._beginMessage(tc.CMD_GET_SIM_VARIABLE, tc.FIND_INTERMODAL_ROUTE, "", 407 1 + 4 + 1 + 4 + len(fromEdge) + 1 + 4 + len(toEdge) + 1 + 4 + len(modes) + 408 1 + 8 + 1 + 4 + 1 + 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1 + 4 + len(pType) + 409 1 + 4 + len(vType) + 1 + 4 + len(destStop)) 410 self._connection._string += struct.pack("!Bi", tc.TYPE_COMPOUND, 13) 411 self._connection._packString(fromEdge) 412 self._connection._packString(toEdge) 413 self._connection._packString(modes) 414 self._connection._string += struct.pack("!BdBi", tc.TYPE_DOUBLE, depart, tc.TYPE_INTEGER, routingMode) 415 self._connection._string += struct.pack("!BdBd", tc.TYPE_DOUBLE, speed, tc.TYPE_DOUBLE, walkFactor) 416 self._connection._string += struct.pack("!BdBd", tc.TYPE_DOUBLE, departPos, tc.TYPE_DOUBLE, arrivalPos) 417 self._connection._string += struct.pack("!Bd", tc.TYPE_DOUBLE, departPosLat) 418 self._connection._packString(pType) 419 self._connection._packString(vType) 420 self._connection._packString(destStop) 421 answer = self._connection._checkResult(tc.CMD_GET_SIM_VARIABLE, tc.FIND_INTERMODAL_ROUTE, "") 422 result = [] 423 for c in range(answer.readInt()): 424 answer.read("!B") # Type 425 result.append(_readStage(answer)) 426 return result 427 428 def clearPending(self, routeID=""): 429 self._connection._beginMessage(tc.CMD_SET_SIM_VARIABLE, tc.CMD_CLEAR_PENDING_VEHICLES, "", 430 1 + 4 + len(routeID)) 431 self._connection._packString(routeID) 432 self._connection._sendExact() 433 434 def saveState(self, fileName): 435 self._connection._beginMessage(tc.CMD_SET_SIM_VARIABLE, tc.CMD_SAVE_SIMSTATE, "", 436 1 + 4 + len(fileName)) 437 self._connection._packString(fileName) 438 self._connection._sendExact() 439 440 def subscribe(self, varIDs=(tc.VAR_DEPARTED_VEHICLES_IDS,), begin=0, end=2**31 - 1): 441 """subscribe(list(integer), double, double) -> None 442 443 Subscribe to one or more simulation values for the given interval. 444 """ 445 Domain.subscribe(self, "", varIDs, begin, end) 446 447 def getSubscriptionResults(self): 448 """getSubscriptionResults() -> dict(integer: <value_type>) 449 450 Returns the subscription results for the last time step. 451 It is not possible to retrieve older subscription results than the ones 452 from the last time step. 453 """ 454 return Domain.getSubscriptionResults(self, "") 455 456 457SimulationDomain() 458