1 /****************************************************************************/ 2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo 3 // Copyright (C) 2001-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 MESegment.h 11 /// @author Daniel Krajzewicz 12 /// @date Tue, May 2005 13 /// @version $Id$ 14 /// 15 // A single mesoscopic segment (cell) 16 /****************************************************************************/ 17 #ifndef MESegment_h 18 #define MESegment_h 19 20 21 // =========================================================================== 22 // included modules 23 // =========================================================================== 24 #include <config.h> 25 26 #include <vector> 27 #include <utils/common/Named.h> 28 #include <utils/common/SUMOTime.h> 29 30 31 // =========================================================================== 32 // class declarations 33 // =========================================================================== 34 class MSEdge; 35 class MSLink; 36 class MSMoveReminder; 37 class MSVehicleControl; 38 class MEVehicle; 39 class BinaryInputDevice; 40 class OutputDevice; 41 42 43 // =========================================================================== 44 // class definitions 45 // =========================================================================== 46 /** 47 * @class MESegment 48 * @brief A single mesoscopic segment (cell) 49 */ 50 class MESegment : public Named { 51 public: 52 /** @brief constructor 53 * @param[in] id The id of this segment (currently: "<EDGEID>:<SEGMENTNO>") 54 * @param[in] parent The edge this segment is located within 55 * @param[in] next The following segment (belonging to the same edge) 56 * @param[in] length The segment's length 57 * @param[in] speed The speed allowed on this segment 58 * @param[in] idx The running index of this segment within the segment's edge 59 * @param[in] tauff The factor for free-free headway time 60 * @param[in] taufj The factor for free-jam headway time 61 * @param[in] taujf The factor for jam-free headway time 62 * @param[in] taujj The factor for jam-jam headway time 63 * @param[in] jamThresh percentage of occupied space before the segment is jammed 64 * @param[in] multiQueue whether to install multiple queues on this segment 65 * @param[in] junctionControl whether junction control is enabled on this segment 66 * @param[in] the quotient of geometrical length / given length 67 * @todo recheck the id; using a ':' as divider is not really nice 68 */ 69 MESegment(const std::string& id, 70 const MSEdge& parent, MESegment* next, 71 double length, double speed, 72 int idx, 73 SUMOTime tauff, SUMOTime taufj, 74 SUMOTime taujf, SUMOTime taujj, 75 double jamThresh, 76 bool multiQueue, bool junctionControl); 77 78 79 typedef std::vector<MEVehicle*> Queue; 80 typedef std::vector<Queue> Queues; 81 /// @name Measure collection 82 /// @{ 83 84 /** @brief Adds a data collector for a detector to this segment 85 * 86 * @param[in] data The data collector to add 87 */ 88 void addDetector(MSMoveReminder* data); 89 90 /** @brief Removes a data collector for a detector from this segment 91 * 92 * @param[in] data The data collector to remove 93 */ 94 void removeDetector(MSMoveReminder* data); 95 96 /** @brief Updates data of a detector for all vehicle queues 97 * 98 * @param[in] data The detector data to update 99 */ 100 void prepareDetectorForWriting(MSMoveReminder& data); 101 /// @} 102 103 /** @brief Returns whether the given vehicle would still fit into the segment 104 * 105 * @param[in] veh The vehicle to check space for 106 * @param[in] entryTime The time at which the vehicle wants to enter 107 * @param[in] init whether the check is done at insertion time 108 * @return true if the vehicle may be added to this segment, false otherwise 109 */ 110 bool hasSpaceFor(const MEVehicle* veh, SUMOTime entryTime, bool init = false) const; 111 112 /** @brief Inserts (emits) vehicle into the segment 113 * 114 * @param[in] veh The vehicle to emit 115 * @param[in] time The emission time 116 * @return Whether the emission was successful 117 */ 118 bool initialise(MEVehicle* veh, SUMOTime time); 119 120 /** @brief Returns the total number of cars on the segment 121 * 122 * @return the total number of cars on the segment 123 */ getCarNumber()124 inline int getCarNumber() const { 125 return myNumCars; 126 } 127 128 /// @brief return the number of queues numQueues()129 inline int numQueues() const { 130 return (int)myCarQues.size(); 131 } 132 /** @brief Returns the cars in the queue with the given index for visualization 133 * @return the Queue (XXX not thread-safe!) 134 */ getQueue(int index)135 inline const Queue& getQueue(int index) const { 136 assert(index < (int)myCarQues.size()); 137 return myCarQues[index]; 138 } 139 140 /** @brief Returns the running index of the segment in the edge (0 is the most upstream). 141 * 142 * @return the running index of the segment in the edge 143 */ getIndex()144 inline int getIndex() const { 145 return myIndex; 146 } 147 148 /** @brief Returns the following segment on the same edge (0 if it is the last). 149 * 150 * @return the following segment on the same edge (0 if it is the last) 151 */ getNextSegment()152 inline MESegment* getNextSegment() const { 153 return myNextSegment; 154 } 155 156 /** @brief Returns the length of the segment in meters. 157 * 158 * @return the length of the segment 159 */ getLength()160 inline double getLength() const { 161 return myLength; 162 } 163 164 /** @brief Returns the occupany of the segment (the sum of the vehicle lengths + minGaps) 165 * 166 * @return the occupany of the segment in meters 167 */ getBruttoOccupancy()168 inline double getBruttoOccupancy() const { 169 return myOccupancy; 170 } 171 172 173 /** @brief Returns the relative occupany of the segment (percentage of road used)) 174 * @return the occupany of the segment in percent 175 */ getRelativeOccupancy()176 inline double getRelativeOccupancy() const { 177 return myOccupancy / myCapacity; 178 } 179 180 /** @brief Returns the relative occupany of the segment (percentage of road used)) 181 * at which the segment is considered jammed 182 * @return the jam treshold of the segment in percent 183 */ getRelativeJamThreshold()184 inline double getRelativeJamThreshold() const { 185 return myJamThreshold / myCapacity; 186 } 187 188 /** @brief Returns the average speed of vehicles on the segment in meters per second. 189 * If there is no vehicle on the segment it returns the maximum allowed speed 190 * @param[in] useCache whether to use a cached value if available 191 * @note this value is cached in myMeanSpeed. Since caching only takes place 192 * once every simstep there is a potential for side-influences (i.e. GUI calls to 193 * this method, ...) For that reason the simulation logic doesn't use the cache. 194 * This shouldn't matter much for speed since it is only used during 195 * initializsation of vehicles onto the segment. 196 * @return the average speed on the segment 197 */ 198 double getMeanSpeed(bool useCache) const; 199 200 /// @brief wrapper to satisfy the FunctionBinding signature getMeanSpeed()201 inline double getMeanSpeed() const { 202 return getMeanSpeed(true); 203 } 204 205 206 void writeVehicles(OutputDevice& of) const; 207 208 /** @brief Removes the given car from the edge's que 209 * 210 * @param[in] v The vehicle to remove 211 * @param[in] leaveTime The time at which the vehicle is leaving the que 212 * @param[in] reason The reason for removing to send to reminders 213 * @return The next first vehicle to add to the net's que 214 */ 215 MEVehicle* removeCar(MEVehicle* v, SUMOTime leaveTime, const MSMoveReminder::Notification reason); 216 217 /** @brief Returns the link the given car will use when passing the next junction 218 * 219 * This returns non-zero values only for the last segment and only 220 * if junction control is enabled. 221 * 222 * @param[in] veh The vehicle in question 223 * @param[in] tlsPenalty Whether the link should be returned for computing tlsPenalty 224 * @return The link to use or 0 without junction control 225 */ 226 MSLink* getLink(const MEVehicle* veh, bool tlsPenalty = false) const; 227 228 /** @brief Returns whether the vehicle may use the next link 229 * 230 * In case of disabled junction control it returns always true. 231 * 232 * @param[in] veh The vehicle in question 233 * @return Whether it may pass to the next segment 234 */ 235 bool isOpen(const MEVehicle* veh) const; 236 237 /** @brief Removes the vehicle from the segment, adapting its parameters 238 * 239 * @param[in] veh The vehicle in question 240 * @param[in] next The subsequent segment for delay calculation 241 * @param[in] time the leave time 242 * @todo Isn't always time == veh->getEventTime? 243 */ 244 void send(MEVehicle* veh, MESegment* next, SUMOTime time, const MSMoveReminder::Notification reason); 245 246 /** @brief Adds the vehicle to the segment, adapting its parameters 247 * 248 * @param[in] veh The vehicle in question 249 * @param[in] time the leave time 250 * @param[in] isDepart whether the vehicle just departed 251 * @todo Isn't always time == veh->getEventTime? 252 */ 253 void receive(MEVehicle* veh, SUMOTime time, bool isDepart = false, bool afterTeleport = false); 254 255 256 /** @brief tries to remove any car from this segment 257 * 258 * @param[in] currentTime the current time 259 * @return Whether vaporization was successful 260 * @note: cars removed via this method do NOT count as arrivals */ 261 bool vaporizeAnyCar(SUMOTime currentTime); 262 263 /** @brief Returns the edge this segment belongs to 264 * @return the edge this segment belongs to 265 */ getEdge()266 inline const MSEdge& getEdge() const { 267 return myEdge; 268 } 269 270 271 /** @brief reset mySpeed and patch the speed of 272 * all vehicles in it. Also set/recompute myJamThreshold 273 * @param[in] jamThresh follows the semantic of option meso-jam-threshold 274 */ 275 void setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh = DO_NOT_PATCH_JAM_THRESHOLD); 276 277 /** @brief Returns the (planned) time at which the next vehicle leaves this segment 278 * @return The time the vehicle thinks it leaves 279 */ 280 SUMOTime getEventTime() const; 281 282 /// @brief Like getEventTime but returns seconds (for visualization) getEventTimeSeconds()283 inline double getEventTimeSeconds() const { 284 return STEPS2TIME(getEventTime()); 285 } 286 287 /// @brief get the last headway time in seconds getLastHeadwaySeconds()288 inline double getLastHeadwaySeconds() const { 289 return STEPS2TIME(myLastHeadway); 290 } 291 292 /// @brief get the last headway time in seconds getEntryBlockTimeSeconds()293 inline double getEntryBlockTimeSeconds() const { 294 return STEPS2TIME(myEntryBlockTime); 295 } 296 297 /// @name State saving/loading 298 /// @{ 299 300 /** @brief Saves the state of this segment into the given stream 301 * 302 * Some internal values which must be restored are saved as well as ids of 303 * the vehicles stored in internal queues and the last departures of connected 304 * edges. 305 * 306 * @param[in, filled] out The (possibly binary) device to write the state into 307 * @todo What about throwing an IOError? 308 */ 309 void saveState(OutputDevice& out); 310 311 /** @brief Loads the state of this segment with the given parameters 312 * 313 * This method is called for every internal que the segment has. 314 * Every vehicle is retrieved from the given MSVehicleControl and added to this 315 * segment. Then, the internal queues that store vehicles dependant to their next 316 * edge are filled the same way. Then, the departure of last vehicles onto the next 317 * edge are restored. 318 * 319 * @param[in] vehIDs The vehicle ids for the current que 320 * @param[in] vc The vehicle control to retrieve references vehicles from 321 * @param[in] blockTime The time the last vehicle left the que 322 * @param[in] queIdx The index of the current que 323 * @todo What about throwing an IOError? 324 * @todo What about throwing an error if something else fails (a vehicle can not be referenced)? 325 */ 326 void loadState(const std::vector<std::string>& vehIDs, MSVehicleControl& vc, const SUMOTime blockTime, const int queIdx); 327 /// @} 328 329 330 /** @brief returns all vehicles (for debugging) 331 */ 332 std::vector<const MEVehicle*> getVehicles() const; 333 334 335 /** @brief returns flow based on headway 336 * @note: returns magic number 10000 when headway cannot be computed 337 */ 338 double getFlow() const; 339 340 341 /// @brief whether the given segment is 0 or encodes vaporization isInvalid(const MESegment * segment)342 static inline bool isInvalid(const MESegment* segment) { 343 return segment == 0 || segment == &myVaporizationTarget; 344 } 345 346 /// @brief return a time after earliestEntry at which a vehicle may be inserted at full speed 347 SUMOTime getNextInsertionTime(SUMOTime earliestEntry) const; 348 349 /** @brief return whether this segment is considered free as opposed to jammed 350 */ free()351 inline bool free() const { 352 return myOccupancy <= myJamThreshold; 353 } 354 355 /// @brief return the remaining physical space on this segment remainingVehicleCapacity(const double vehLength)356 inline int remainingVehicleCapacity(const double vehLength) const { 357 if (myOccupancy == 0. && myCapacity < vehLength) { 358 // even small segments can hold at least one vehicle 359 return 1; 360 } 361 return (int)((myCapacity - myOccupancy) / vehLength); 362 } 363 364 /// @brief return the next time at which a vehicle my enter this segment getEntryBlockTime()365 inline SUMOTime getEntryBlockTime() const { 366 return myEntryBlockTime; 367 } 368 369 /// @brief set the next time at which a vehicle my enter this segment setEntryBlockTime(SUMOTime entryBlockTime)370 inline void setEntryBlockTime(SUMOTime entryBlockTime) { 371 myEntryBlockTime = entryBlockTime; 372 } 373 374 /// @brief return the minimum headway-time with which vehicles may enter or leave this segment getMinimumHeadwayTime()375 inline SUMOTime getMinimumHeadwayTime() const { 376 return myTau_ff; 377 } 378 379 static const double DO_NOT_PATCH_JAM_THRESHOLD; 380 381 /// @brief add this lanes MoveReminders to the given vehicle 382 void addReminders(MEVehicle* veh) const; 383 384 /** @brief Returns the penalty time for passing a link (if using gMesoTLSPenalty > 0 or gMesoMinorPenalty > 0) 385 * @param[in] veh The vehicle in question 386 * @return The time penalty 387 */ 388 SUMOTime getLinkPenalty(const MEVehicle* veh) const; 389 390 /** @brief Returns the average green time as fraction of cycle time 391 * @param[in] veh The vehicle in question for determining the link 392 * @return The green fraction or 1 if the vehicle does not continue after this edge 393 */ 394 double getTLSCapacity(const MEVehicle* veh) const; 395 396 private: 397 bool overtake(); 398 399 SUMOTime getTimeHeadway(const MESegment* pred, const MEVehicle* veh); 400 401 void setSpeedForQueue(double newSpeed, SUMOTime currentTime, 402 SUMOTime blockTime, const std::vector<MEVehicle*>& vehs); 403 404 /** @brief compute the new arrival time when switching speed 405 */ 406 SUMOTime newArrival(const MEVehicle* const v, double newSpeed, SUMOTime currentTime); 407 408 /// @brief whether a leader in any queue is blocked 409 bool hasBlockedLeader() const; 410 411 /** @brief compute a value for myJamThreshold 412 * if jamThresh is negative, compute a value which allows free flow at mySpeed 413 * interpret jamThresh as the relative occupation at which jam starts 414 */ 415 void recomputeJamThreshold(double jamThresh); 416 417 /// @brief compute jam threshold for the given speed and jam-threshold option 418 double jamThresholdForSpeed(double speed, double jamThresh) const; 419 420 /// @brief whether the given link may be passed because the option meso-junction-control.limited is set 421 bool limitedControlOverride(const MSLink* link) const; 422 423 /// @brief return the maximum tls penalty for all links from this edge 424 double getMaxPenaltySeconds() const; 425 426 /// @brief whether the segment requires use of multiple queues 427 static bool useMultiQueue(bool multiQueue, const MSEdge& parent); 428 429 /// @brief convert net time gap (leader back to follower front) to gross time gap (leader front to follower front) tauWithVehLength(SUMOTime tau,double lengthWithGap)430 inline SUMOTime tauWithVehLength(SUMOTime tau, double lengthWithGap) const { 431 return tau + (SUMOTime)(lengthWithGap / myTau_length); 432 } 433 434 private: 435 /// @brief The microsim edge this segment belongs to 436 const MSEdge& myEdge; 437 438 /// @brief The next segment of this edge, 0 if this is the last segment of this edge 439 MESegment* myNextSegment; 440 441 /// @brief The segment's length 442 const double myLength; 443 444 /// @brief Running number of the segment in the edge 445 const int myIndex; 446 447 /// @brief The time headway parameters, see the Eissfeldt thesis 448 const SUMOTime myTau_ff, myTau_fj, myTau_jf, myTau_jj; 449 /// @brief Headway parameter for computing gross time headyway from net time headway, length and edge speed 450 double myTau_length; 451 452 /// @brief slope and axis offset for the jam-jam headway function 453 double myA, myB; 454 455 /// @brief The capacity of the segment in number of cars, used only in time headway calculation 456 /// This parameter has only an effect if tau_jf != tau_jj, which is not(!) the case per default 457 const double myHeadwayCapacity; 458 459 /// @brief The number of lanes * the length 460 const double myCapacity; 461 462 /// @brief The occupied space (in m) on the segment 463 double myOccupancy; 464 465 /// @brief Whether junction control is enabled 466 const bool myJunctionControl; 467 468 /// @brief Whether tls penalty is enabled 469 const bool myTLSPenalty; 470 471 /// @brief Whether minor penalty is enabled 472 const bool myMinorPenalty; 473 474 /// @brief The space (in m) which needs to be occupied before the segment is considered jammed 475 double myJamThreshold; 476 477 /// @brief The data collection for all kinds of detectors 478 std::vector<MSMoveReminder*> myDetectorData; 479 480 /// @brief The car queues. Vehicles are inserted in the front and removed in the back 481 Queues myCarQues; 482 483 /// @brief The cached value for the number of cars 484 int myNumCars; 485 486 /// @brief The follower edge to que index mapping for multi queue segments 487 std::map<const MSEdge*, std::vector<int> > myFollowerMap; 488 489 /// @brief The block times 490 std::vector<SUMOTime> myBlockTimes; 491 492 /* @brief The block time for vehicles who wish to enter this segment. 493 * @note since we do not know which queue will be used there is only one 494 * value for all queues */ 495 SUMOTime myEntryBlockTime; 496 497 /// @brief the last headway 498 SUMOTime myLastHeadway; 499 500 /* @brief segment for signifying vaporization. This segment has invalid 501 * data and should only be used as a unique pointer */ 502 static MSEdge myDummyParent; 503 static MESegment myVaporizationTarget; 504 505 /// @brief the mean speed on this segment. Updated at event time or on demand 506 mutable double myMeanSpeed; 507 508 /// @brief the time at which myMeanSpeed was last updated 509 mutable SUMOTime myLastMeanSpeedUpdate; 510 511 private: 512 /// @brief Invalidated copy constructor. 513 MESegment(const MESegment&); 514 515 /// @brief Invalidated assignment operator. 516 MESegment& operator=(const MESegment&); 517 518 /// @brief constructor for dummy segment 519 MESegment(const std::string& id); 520 }; 521 522 523 #endif 524 525 /****************************************************************************/ 526