1 /****************************************************************************/ 2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo 3 // Copyright (C) 2013-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 MSDevice_SSM.h 11 /// @author Daniel Krajzewicz 12 /// @author Jakob Erdmann 13 /// @author Leonhard Luecken 14 /// @date 11.06.2013 15 /// @version $Id$ 16 /// 17 // An SSM-device logs encounters / conflicts of the carrying vehicle with other surrounding vehicles. 18 // XXX: Preliminary implementation. Use with care. Especially rerouting vehicles could be problematic. 19 /****************************************************************************/ 20 #ifndef MSDevice_SSM_h 21 #define MSDevice_SSM_h 22 23 24 // =========================================================================== 25 // included modules 26 // =========================================================================== 27 #include <config.h> 28 29 #include <queue> 30 #include "MSVehicleDevice.h" 31 #include <utils/common/SUMOTime.h> 32 #include <utils/iodevices/OutputDevice_File.h> 33 #include <utils/geom/Position.h> 34 35 36 // =========================================================================== 37 // class declarations 38 // =========================================================================== 39 class SUMOVehicle; 40 class SUMOTrafficObject; 41 42 43 // =========================================================================== 44 // class definitions 45 // =========================================================================== 46 /** 47 * @class MSDevice_SSM 48 * @brief A device which collects info on the vehicle trip (mainly on departure and arrival) 49 * 50 * Each device collects departure time, lane and speed and the same for arrival. 51 * 52 * @see MSDevice 53 */ 54 55 class MSCrossSection; 56 57 class MSDevice_SSM : public MSVehicleDevice { 58 59 private: 60 /// All currently existing SSM devices 61 static std::set<MSDevice_SSM*>* instances; 62 63 public: 64 /// @brief Different types of encounters corresponding to relative positions of the vehicles. 65 /// The name describes the type from the ego perspective 66 enum EncounterType { 67 // Other vehicle is closer than range, but not on a lane conflicting with the ego's route ahead 68 ENCOUNTER_TYPE_NOCONFLICT_AHEAD = 0, //!< ENCOUNTER_TYPE_NOCONFLICT_AHEAD 69 // Ego and foe vehicles' edges form a part of a consecutive sequence of edges 70 // This type may be specified further by ENCOUNTER_TYPE_FOLLOWING_LEADER or ENCOUNTER_TYPE_FOLLOWING_FOLLOWER 71 ENCOUNTER_TYPE_FOLLOWING = 1, //!< ENCOUNTER_TYPE_FOLLOWING 72 // Ego vehicle is on an edge that has a sequence of successors connected to the other vehicle's edge 73 ENCOUNTER_TYPE_FOLLOWING_FOLLOWER = 2, //!< ENCOUNTER_TYPE_FOLLOWING_FOLLOWER 74 // Other vehicle is on an edge that has a sequence of successors connected to the ego vehicle's current edge 75 ENCOUNTER_TYPE_FOLLOWING_LEADER = 3, //!< ENCOUNTER_TYPE_FOLLOWING_LEADER 76 // Other vehicle is on an edge that has a sequence of successors connected to the ego vehicle's current edge 77 ENCOUNTER_TYPE_ON_ADJACENT_LANES = 4, //!< ENCOUNTER_TYPE_ON_ADJACENT_LANES 78 // Ego and foe share an upcoming edge of their routes while the merging point for the routes is still ahead 79 // This type may be specified further by ENCOUNTER_TYPE_MERGING_LEADER or ENCOUNTER_TYPE_MERGING_FOLLOWER 80 ENCOUNTER_TYPE_MERGING = 5, //!< ENCOUNTER_TYPE_MERGING 81 // Other vehicle is on an edge that has a sequence of successors connected to an edge on the ego vehicle's route 82 // and the estimated arrival vehicle at the merge point is earlier for the ego than for the foe 83 ENCOUNTER_TYPE_MERGING_LEADER = 6, //!< ENCOUNTER_TYPE_MERGING_LEADER 84 // Other vehicle is on an edge that has a sequence of successors connected to an edge on the ego vehicle's route 85 // and the estimated arrival vehicle at the merge point is earlier for the foe than for the ego 86 ENCOUNTER_TYPE_MERGING_FOLLOWER = 7,//!< ENCOUNTER_TYPE_MERGING_FOLLOWER 87 // Vehicles' bestlanes lead to the same edge but to adjacent lanes 88 ENCOUNTER_TYPE_MERGING_ADJACENT = 8,//!< ENCOUNTER_TYPE_MERGING_ADJACENT 89 // Ego's and foe's routes have crossing edges 90 // This type may be specified further by ENCOUNTER_TYPE_CROSSING_LEADER or ENCOUNTER_TYPE_CROSSING_FOLLOWER 91 ENCOUNTER_TYPE_CROSSING = 9, //!< ENCOUNTER_TYPE_CROSSING 92 // Other vehicle is on an edge that has a sequence of successors leading to an internal edge that crosses the ego vehicle's edge at a junction 93 // and the estimated arrival vehicle at the merge point is earlier for the ego than for the foe 94 ENCOUNTER_TYPE_CROSSING_LEADER = 10, //!< ENCOUNTER_TYPE_CROSSING_LEADER 95 // Other vehicle is on an edge that has a sequence of successors leading to an internal edge that crosses the ego vehicle's edge at a junction 96 // and the estimated arrival vehicle at the merge point is earlier for the foe than for the ego 97 ENCOUNTER_TYPE_CROSSING_FOLLOWER = 11, //!< ENCOUNTER_TYPE_CROSSING_FOLLOWER 98 // The encounter is a possible crossing conflict, and the ego vehicle has entered the conflict area 99 ENCOUNTER_TYPE_EGO_ENTERED_CONFLICT_AREA = 12, //!< ENCOUNTER_TYPE_EGO_ENTERED_CONFLICT_AREA 100 // The encounter is a possible crossing conflict, and the foe vehicle has entered the conflict area 101 ENCOUNTER_TYPE_FOE_ENTERED_CONFLICT_AREA = 13, //!< ENCOUNTER_TYPE_FOE_ENTERED_CONFLICT_AREA 102 // The encounter has been a possible crossing conflict, but the ego vehicle has left the conflict area 103 ENCOUNTER_TYPE_EGO_LEFT_CONFLICT_AREA = 14, //!< ENCOUNTER_TYPE_EGO_LEFT_CONFLICT_AREA 104 // The encounter has been a possible crossing conflict, but the foe vehicle has left the conflict area 105 ENCOUNTER_TYPE_FOE_LEFT_CONFLICT_AREA = 15, //!< ENCOUNTER_TYPE_FOE_LEFT_CONFLICT_AREA 106 // The encounter has been a possible crossing conflict, and both vehicles have entered the conflict area (one must have already left, otherwise this must be a collision) 107 ENCOUNTER_TYPE_BOTH_ENTERED_CONFLICT_AREA = 16, //!< ENCOUNTER_TYPE_BOTH_ENTERED_CONFLICT_AREA 108 // The encounter has been a possible crossing conflict, but both vehicle have left the conflict area 109 ENCOUNTER_TYPE_BOTH_LEFT_CONFLICT_AREA = 17, //!< ENCOUNTER_TYPE_BOTH_LEFT_CONFLICT_AREA 110 // FOLLOWING_PASSED and MERGING_PASSED are reserved to achieve that these encounter types may be tracked longer (see updatePassedEncounter) 111 // The encounter has been a following situation, but is not active any more 112 ENCOUNTER_TYPE_FOLLOWING_PASSED = 18, //!< ENCOUNTER_TYPE_FOLLOWING_PASSED 113 // The encounter has been a merging situation, but is not active any more 114 ENCOUNTER_TYPE_MERGING_PASSED = 19, //!< ENCOUNTER_TYPE_FOLLOWING_PASSED 115 // Collision (currently unused, might be differentiated further) 116 ENCOUNTER_TYPE_COLLISION = 111 //!< ENCOUNTER_TYPE_COLLISION 117 }; 118 toString(EncounterType type)119 static std::string toString(EncounterType type) { 120 switch (type) { 121 case (ENCOUNTER_TYPE_NOCONFLICT_AHEAD): 122 return ("NOCONFLICT_AHEAD"); 123 case (ENCOUNTER_TYPE_FOLLOWING): 124 return ("FOLLOWING"); 125 case (ENCOUNTER_TYPE_FOLLOWING_FOLLOWER): 126 return ("FOLLOWING_FOLLOWER"); 127 case (ENCOUNTER_TYPE_FOLLOWING_LEADER): 128 return ("FOLLOWING_LEADER"); 129 case (ENCOUNTER_TYPE_ON_ADJACENT_LANES): 130 return ("ON_ADJACENT_LANES"); 131 case (ENCOUNTER_TYPE_MERGING): 132 return ("MERGING"); 133 case (ENCOUNTER_TYPE_MERGING_LEADER): 134 return ("MERGING_LEADER"); 135 case (ENCOUNTER_TYPE_MERGING_FOLLOWER): 136 return ("MERGING_FOLLOWER"); 137 case (ENCOUNTER_TYPE_MERGING_ADJACENT): 138 return ("MERGING_ADJACENT"); 139 case (ENCOUNTER_TYPE_CROSSING): 140 return ("CROSSING"); 141 case (ENCOUNTER_TYPE_CROSSING_LEADER): 142 return ("CROSSING_LEADER"); 143 case (ENCOUNTER_TYPE_CROSSING_FOLLOWER): 144 return ("CROSSING_FOLLOWER"); 145 case (ENCOUNTER_TYPE_EGO_ENTERED_CONFLICT_AREA): 146 return ("EGO_ENTERED_CONFLICT_AREA"); 147 case (ENCOUNTER_TYPE_FOE_ENTERED_CONFLICT_AREA): 148 return ("FOE_ENTERED_CONFLICT_AREA"); 149 case (ENCOUNTER_TYPE_EGO_LEFT_CONFLICT_AREA): 150 return ("EGO_LEFT_CONFLICT_AREA"); 151 case (ENCOUNTER_TYPE_FOE_LEFT_CONFLICT_AREA): 152 return ("FOE_LEFT_CONFLICT_AREA"); 153 case (ENCOUNTER_TYPE_BOTH_ENTERED_CONFLICT_AREA): 154 return ("BOTH_ENTERED_CONFLICT_AREA"); 155 case (ENCOUNTER_TYPE_BOTH_LEFT_CONFLICT_AREA): 156 return ("BOTH_LEFT_CONFLICT_AREA"); 157 case (ENCOUNTER_TYPE_FOLLOWING_PASSED): 158 return ("FOLLOWING_PASSED"); 159 case (ENCOUNTER_TYPE_MERGING_PASSED): 160 return ("MERGING_PASSED"); 161 case (ENCOUNTER_TYPE_COLLISION): 162 return ("COLLISION"); 163 } 164 return ("UNKNOWN"); 165 }; 166 167 private: 168 /// @brief An encounter is an episode involving two vehicles, 169 /// which are closer to each other than some specified distance. 170 class Encounter { 171 private: 172 /// @brief A trajectory encloses a series of positions x and speeds v for one vehicle 173 /// (the times are stored only once in the enclosing encounter) 174 struct Trajectory { 175 // positions 176 PositionVector x; 177 // momentary speeds 178 PositionVector v; 179 }; 180 /// @brief ConflictPointInfo stores some information on a specific conflict point 181 /// (used to store information on ssm-extremal values) 182 struct ConflictPointInfo { 183 /// @brief time point of the conflict 184 double time; 185 /// @brief Predicted location of the conflict: 186 /// In case of MERGING and CROSSING: entry point to conflict area for follower 187 /// In case of FOLLOWING: position of leader's back 188 Position pos; 189 /// @brief Type of the conflict 190 EncounterType type; 191 /// @brief value of the corresponding SSM 192 double value; 193 ConflictPointInfoConflictPointInfo194 ConflictPointInfo(double time, Position x, EncounterType type, double ssmValue) : 195 time(time), pos(x), type(type), value(ssmValue) {}; 196 }; 197 198 public: 199 /// @brief Constructor 200 Encounter(const MSVehicle* _ego, const MSVehicle* const _foe, double _begin, double extraTime); 201 /// @brief Destructor 202 ~Encounter(); 203 204 /// @brief add a new data point and update encounter type 205 void add(double time, EncounterType type, Position egoX, Position egoV, Position foeX, Position foeV, 206 Position conflictPoint, double egoDistToConflict, double foeDistToConflict, double ttc, double drac, std::pair<double, double> pet); 207 208 /// @brief Returns the number of trajectory points stored size()209 std::size_t size() const { 210 return timeSpan.size(); 211 } 212 213 /// @brief resets remainingExtraTime to the given value 214 void resetExtraTime(double value); 215 /// @brief decreases myRemaingExtraTime by given amount in seconds 216 void countDownExtraTime(double amount); 217 /// @brief returns the remaining extra time 218 double getRemainingExtraTime() const; 219 220 /// @brief Compares encounters regarding to their start time 221 struct compare { 222 typedef bool value_type; operatorcompare223 bool operator()(Encounter* e1, Encounter* e2) { 224 return e1->begin >= e2->begin; 225 }; 226 }; 227 228 229 230 public: 231 const MSVehicle* ego; 232 const MSVehicle* foe; 233 const std::string egoID; 234 const std::string foeID; 235 double begin, end; 236 EncounterType currentType; 237 238 /// @brief Remaining extra time (decreases after an encounter ended) 239 double remainingExtraTime; 240 241 /// @brief Times when the ego vehicle entered/left the conflict area. Currently only applies for crossing situations. Used for PET calculation. (May be defined for merge conflicts in the future) 242 double egoConflictEntryTime, egoConflictExitTime; 243 /// @brief Times when the foe vehicle entered/left the conflict area. Currently only applies for crossing situations. Used for PET calculation. (May be defined for merge conflicts in the future) 244 double foeConflictEntryTime, foeConflictExitTime; 245 246 /// @brief time points corresponding to the trajectories 247 std::vector<double> timeSpan; 248 /// @brief Evolution of the encounter classification (@see EncounterType) 249 std::vector<int> typeSpan; 250 /// @brief Trajectory of the ego vehicle 251 Trajectory egoTrajectory; 252 /// @brief Trajectory of the foe vehicle 253 Trajectory foeTrajectory; 254 /// Evolution of the ego vehicle's distance to the conflict point 255 std::vector<double> egoDistsToConflict; 256 /// Evolution of the foe vehicle's distance to the conflict point 257 std::vector<double> foeDistsToConflict; 258 259 /// @brief Predicted location of the conflict: 260 /// In case of MERGING and CROSSING: entry point to conflict area for follower 261 /// In case of FOLLOWING: position of leader's back 262 PositionVector conflictPointSpan; 263 264 /// @brief All values for TTC 265 std::vector<double> TTCspan; 266 /// @brief All values for DRAC 267 std::vector<double> DRACspan; 268 269 // /// @brief Cross sections at which a PET shall be calculated for the corresponding vehicle 270 // std::vector<std::pair<std::pair<const MSLane*, double>, double> > egoPETCrossSections; 271 // std::vector<std::pair<std::pair<const MSLane*, double>, double> > foePETCrossSections; 272 273 /// @name Extremal values for the SSMs 274 /// @{ 275 ConflictPointInfo minTTC; 276 ConflictPointInfo maxDRAC; 277 ConflictPointInfo PET; 278 /// @} 279 280 /// @brief this flag is set by updateEncounter() or directly in processEncounters(), where encounters are closed if it is true. 281 bool closingRequested; 282 283 private: 284 /// @brief Invalidated Constructor. 285 Encounter(const Encounter&); 286 /// @brief Invalidated assignment operator. 287 Encounter& operator=(const Encounter&); 288 /// 289 }; 290 291 292 /// @brief Structure to collect some info on the encounter needed during ssm calculation by various functions. 293 struct EncounterApproachInfo { 294 EncounterApproachInfo(Encounter* e); 295 Encounter* encounter; 296 EncounterType type; 297 Position conflictPoint; 298 double egoConflictEntryDist; 299 double foeConflictEntryDist; 300 double egoConflictExitDist; 301 double foeConflictExitDist; 302 double egoEstimatedConflictEntryTime; 303 double foeEstimatedConflictEntryTime; 304 double egoEstimatedConflictExitTime; 305 double foeEstimatedConflictExitTime; 306 double egoConflictAreaLength; 307 double foeConflictAreaLength; 308 bool egoLeftConflict; 309 bool foeLeftConflict; 310 double ttc; 311 double drac; 312 std::pair<double, double> pet; 313 std::pair<const MSLane*, double> egoConflictEntryCrossSection; 314 std::pair<const MSLane*, double> foeConflictEntryCrossSection; 315 }; 316 317 318 /// A new FoeInfo is created during findSurroundingVehicles() to memorize, where the potential conflict 319 /// corresponding to the encounter might occur. Each FoeInfo ends up in a call to updateEncounter() and 320 /// is deleted there. 321 struct FoeInfo { 322 const MSLane* egoConflictLane; 323 double egoDistToConflictLane; 324 }; 325 // TODO: consider introducing a class foeCollector, which holds the foe info content 326 // plus a vehicle container to be used in findSurrounding vehicles. 327 // findSurroundingVehicles() would then deliver a vector of such foeCollectors 328 // (one for each possible egoConflictLane) instead of a map vehicle->foeInfo 329 // This could be helpful to resolve the resolution for several different 330 // projected conflicts with the same foe. 331 332 333 typedef std::priority_queue<Encounter*, std::vector<Encounter*>, Encounter::compare> EncounterQueue; 334 typedef std::vector<Encounter*> EncounterVector; 335 typedef std::map<const MSVehicle*, FoeInfo*> FoeInfoMap; 336 public: 337 338 /** @brief Inserts MSDevice_SSM-options 339 * @param[filled] oc The options container to add the options to 340 */ 341 static void insertOptions(OptionsCont& oc); 342 343 344 /** @brief Build devices for the given vehicle, if needed 345 * 346 * The options are read and evaluated whether a example-device shall be built 347 * for the given vehicle. 348 * 349 * The built device is stored in the given vector. 350 * 351 * @param[in] v The vehicle for which a device may be built 352 * @param[filled] into The vector to store the built device in 353 */ 354 static void buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into); 355 356 357 /** @brief returns all currently existing SSM devices 358 */ 359 static const std::set<MSDevice_SSM*>& getInstances(); 360 361 /** @brief This is called once per time step in MSNet::writeOutput() and 362 * collects the surrounding vehicles, updates information on encounters 363 * and flushes the encounters qualified as conflicts (@see thresholds) 364 * to the output file. 365 */ 366 void updateAndWriteOutput(); 367 368 private: 369 void update(); 370 void writeOutConflict(Encounter* e); 371 372 /// @brief convert SUMO-positions to geo coordinates (in place) 373 static void toGeo(Position& x); 374 /// @brief convert SUMO-positions to geo coordinates (in place) 375 static void toGeo(PositionVector& x); 376 377 public: 378 /** @brief Clean up remaining devices instances 379 */ 380 static void cleanup(); 381 382 383 public: 384 /// @brief Destructor. 385 ~MSDevice_SSM(); 386 387 388 /** @brief Returns all vehicles, which are within the given range of the given vehicle. 389 * @note all vehicles behind and in front are collected, 390 * including vehicles on confluent edges. For instance, if the range is 20 m. and 391 * a junction lies 10 m. ahead, an upstream scan of 20 m. is performed 392 * for all incoming edges. 393 * 394 * @param veh The ego vehicle, that forms the origin for the scan 395 * @param range The range to be scanned. 396 * @param[in/out] foeCollector container for all collected vehicles 397 * @return All vehicles within range from veh 398 */ 399 static void findSurroundingVehicles(const MSVehicle& veh, double range, FoeInfoMap& foeCollector); 400 401 /** @brief Collects all vehicles within range 'range' upstream of the position 'pos' on the edge 'edge' into foeCollector 402 */ 403 static void getUpstreamVehicles(const MSEdge* edge, double pos, double range, double egoDistToConflictLane, const MSLane* const egoConflictLane, FoeInfoMap& foeCollector, std::set<const MSJunction*>& seenJunctions); 404 405 /** @brief Collects all vehicles on the junction into foeCollector 406 */ 407 static void getVehiclesOnJunction(const MSJunction*, double egoDistToConflictLane, const MSLane* const egoConflictLane, FoeInfoMap& foeCollector); 408 409 410 /// @name Methods called on vehicle movement / state change, overwriting MSDevice 411 /// @{ 412 413 /** @brief Checks for waiting steps when the vehicle moves 414 * 415 * @param[in] veh Vehicle that notifies. 416 * @param[in] oldPos Position before move. 417 * @param[in] newPos Position after move with newSpeed. 418 * @param[in] newSpeed Moving speed. 419 * 420 * @return Always true to keep the device as it cannot be thrown away 421 */ 422 bool notifyMove(SUMOTrafficObject& veh, double oldPos, 423 double newPos, double newSpeed); 424 425 426 /** @brief Called whenever the holder enteres a lane 427 * 428 * @param[in] veh The entering vehicle. 429 * @param[in] reason Reason for leaving the lane 430 * @param[in] enteredLane The lane entered. 431 * @return Always true to keep the device as it cannot be thrown away 432 * @see MSMoveReminder::notifyEnter 433 * @see MSMoveReminder::Notification 434 */ 435 bool notifyEnter(SUMOTrafficObject& veh, MSMoveReminder::Notification reason, const MSLane* enteredLane = 0); 436 437 438 /** @brief Called whenever the holder leaves a lane 439 * 440 * @param[in] veh The leaving vehicle. 441 * @param[in] lastPos Position on the lane when leaving. 442 * @param[in] reason Reason for leaving the lane 443 * @param[in] enteredLane The lane entered. 444 * @return True if it did not leave the net. 445 */ 446 bool notifyLeave(SUMOTrafficObject& veh, double lastPos, 447 MSMoveReminder::Notification reason, const MSLane* enteredLane = 0); 448 /// @} 449 450 451 /// @brief return the name for this type of device deviceName()452 const std::string deviceName() const { 453 return "ssm"; 454 } 455 456 /** @brief Finalizes output. Called on vehicle removal 457 * 458 * @param[in] os The stream to write the information into 459 * @exception IOError not yet implemented 460 * @see MSDevice::generateOutput 461 */ 462 void generateOutput() const; 463 464 465 466 private: 467 /** @brief Constructor 468 * 469 * @param[in] holder The vehicle that holds this device 470 * @param[in] id The ID of the device 471 * @param measures Vector of Surrogate Safety Measure IDs 472 * @param thresholds Vector of corresponding thresholds 473 * @param trajectories Flag indicating whether complete trajectories should be saved for an encounter (if false only extremal values are logged) 474 * @param range Detection range. For vehicles closer than this distance from the ego vehicle, SSMs are traced 475 * @param extraTime Extra time in seconds to be logged after a conflict is over 476 * @param useGeoCoords Whether coordinates should be written out in the original coordinate reference system or as sumo's x,y values 477 */ 478 MSDevice_SSM(SUMOVehicle& holder, const std::string& id, std::string outputFilename, std::map<std::string, double> thresholds, 479 bool trajectories, double range, double extraTime, bool useGeoCoords); 480 481 /** @brief Finds encounters for which the foe vehicle has disappeared from range. 482 * remainingExtraTime is decreased until it reaches zero, which triggers closing the encounter. 483 * If an ended encounter is qualified as a conflict, it is transferred to myPastConflicts 484 * All vehicles for which an encounter instance already exists (vehicle is already tracked) 485 * are removed from 'foes' during processing. 486 * @param[in] foes Foe vehicles that have been found by findSurroundingVehicles() 487 * @param[in] forceClose whether encounters for which the foe is not in range shall be closed immediately, disregarding the remaining extra time (is requested by resetEncounters()). 488 */ 489 void processEncounters(FoeInfoMap& foes, bool forceClose = false); 490 491 492 /** @brief Closes encounters, whose duration exceeds the maximal encounter length. If it is classified as conflict, the encounter is saved. 493 * In any case, a new active encounter is created holding the trailing part (of length myOverlapTime) of the original. 494 */ 495 void storeEncountersExceedingMaxLength(); 496 497 498 499 /** @brief Makes new encounters for all given vehicles (these should be the ones entering the device's range in the current timestep) 500 */ 501 void createEncounters(FoeInfoMap& foes); 502 503 504 /** @brief Stores measures, that are not associated to a specific encounter as headways and brake rates 505 * @todo Manage as episodes (BR -> braking episode, SGAP/TGAP -> car-following episode) with invariant leader, and filtering applying the 506 * corresponding thresholds. 507 */ 508 void computeGlobalMeasures(); 509 510 /** @brief Closes all current Encounters and moves conflicts to myPastConflicts, @see processEncounters 511 */ 512 void resetEncounters(); 513 514 /** @brief Writes out all past conflicts that have begun earlier than the oldest active encounter 515 * @param[in] all Whether all conflicts should be flushed or only those for which no active encounters with earlier begin can exist 516 */ 517 void flushConflicts(bool all = false); 518 519 /** @brief Write out all non-encounter specific measures as headways and braking rates. 520 * @todo Adapt accordingly if episode structure is implemented, @see computeGlobalMeasures() 521 */ 522 void flushGlobalMeasures(); 523 524 /** @brief Updates the encounter (adds a new trajectory point) and deletes the foeInfo. 525 * @return Returns false for new encounters, which should not be kept (if one vehicle has 526 * already left the conflict zone at encounter creation). True, otherwise. 527 */ 528 bool updateEncounter(Encounter* e, FoeInfo* foeInfo); 529 530 /** @brief Updates an encounter, which was classified as ENCOUNTER_TYPE_NOCONFLICT_AHEAD 531 * this may be the case because the foe is out of the detection range but the encounter 532 * is still in extra time (in this case foeInfo==0), or because the foe does not head for a lane conflicting with 533 * the route of the ego vehicle. 534 * It is also used for an ongoing crossing conflict, where only the covered distances are traced 535 * until the situation is over. (A crossing conflict is ongoing, if one vehicle entered the conflict area) 536 * Writes the type of encounter which is determined for the current state into eInfo. And if appropriate some 537 * information concerning vehicles positions in relation to a crossed crossing point (for PET calculation). 538 */ 539 void updatePassedEncounter(Encounter* e, FoeInfo* foeInfo, EncounterApproachInfo& eInfo); 540 541 542 /** @brief Classifies the current type of the encounter provided some information on the opponents 543 * @param[in] foeInfo Info on distance to conflict point for the device holder. 544 * @param[in/out] eInfo Info structure for the current state of the encounter (provides a pointer to the encounter). 545 * @return Returns an encounter type and writes a value to the relevant distances (egoEncounterDist, foeEncounterDist members of eInfo), 546 * i.e. the distances to the entry points to the potential conflict. 547 * @note: The encounter distance has a different meaning for different types of encounters: 548 * 1) For rear-end conflicts (lead/follow situations) the follower's encounter distance is the distance to the actual back position of the leader. The leaders's distance is undefined. 549 * 2) For merging encounters the encounter distance is the distance until the begin of the common target edge/lane. 550 * 3) For crossing encounters the encounter distance is the distance until crossing point of the conflicting lanes. 551 */ 552 EncounterType classifyEncounter(const FoeInfo* foeInfo, EncounterApproachInfo& eInfo) const; 553 554 555 /** @brief Calculates the (x,y)-coordinate for the eventually predicted conflict point and stores the result in 556 * eInfo.conflictPoint. In case of MERGING and CROSSING, this is the entry point to conflict area for follower 557 * In case of FOLLOWING it is the position of leader's back. 558 * @param[in/out] eInfo Info structure for the current state of the encounter. 559 */ 560 static void determineConflictPoint(EncounterApproachInfo& eInfo); 561 562 563 /** @brief Estimates the time until conflict for the vehicles based on the distance to the conflict entry points. 564 * For acceleration profiles, we assume that the acceleration is <= 0 (that is, braking is extrapolated, 565 * while for acceleration it is assumed that the vehicle will continue with its current speed) 566 * @param[in/out] eInfo Info structure for the current state of the encounter. 567 * @note The '[in]'-part for eInfo are its members e->ego, e->foe (to access the vehicle parameters), egoConflictEntryDist, foeConflictEntryDist, i.e., distances to the conflict entry points. 568 * The '[out]'-part for eInfo are its members type (type information may be refined) egoConflictEntryTime, foeConflictEntryTime (estimated times until the conflict entry point is reached) 569 * and egoConflictExitTime, foeConflictExitTime (estimated time until the conflict exit point is reached). 570 * Further the type of the encounter as determined by classifyEncounter(), is refined for the cases CROSSING and MERGING here. 571 */ 572 static void estimateConflictTimes(EncounterApproachInfo& eInfo); 573 574 575 /** @brief Checks whether ego or foe have entered or left the conflict area in the last step and eventually writes 576 * the corresponding entry or exit times to eInfo.encounter. For ongoing crossing conflicts, it also manages 577 * the evolution of the conflict type. 578 * @param[in/out] eInfo Info structure for the current state of the encounter. 579 * @note The times are to be used for SSM computation in computeSSMs(), e.g. in determinePET() 580 */ 581 static void checkConflictEntryAndExit(EncounterApproachInfo& eInfo); 582 583 584 /** @brief Computes the conflict lane for the foe 585 * 586 * @param foe Foe vehicle 587 * @param egoConflictLane Lane, on which the ego would enter the possible conflict 588 * @param routeToConflict, Series of edges, that were traced back from egoConflictLane during findSurrounding Vehicles, when collecting the foe vehicle 589 * @param[out] distToConflictLane, distance to conflictlane entry link (may be negative if foe is already on the conflict lane) 590 * @return Lane, on which the foe would enter the possible conflict, if foe is not on conflict course, Null-pointer is returned. 591 */ 592 const MSLane* findFoeConflictLane(const MSVehicle* foe, const MSLane* egoConflictLane, double& distToConflictLane) const; 593 594 /** @brief Finalizes the encounter and calculates SSM values. 595 */ 596 void closeEncounter(Encounter* e); 597 598 /** @brief Tests if the SSM values exceed the threshold for qualification as conflict. 599 */ 600 bool qualifiesAsConflict(Encounter* e); 601 602 /** @brief Compute current values of the logged SSMs (myMeasures) for the given encounter 'e' 603 * and update 'e' accordingly (add point to SSM time-series, update maximal/minimal value) 604 * This is called just after adding the current vehicle positions and velocity vectors to the encounter. 605 */ 606 void computeSSMs(EncounterApproachInfo& e) const; 607 608 609 /** @brief Discriminates between different encounter types and correspondingly determines the PET for those cases 610 * and writes the result to eInfo.pet (after both vehicles have left the conflict area) 611 */ 612 void determinePET(EncounterApproachInfo& eInfo) const; 613 614 615 /** @brief Discriminates between different encounter types and correspondingly determines TTC and DRAC for those cases 616 * and writes the result to eInfo.ttc and eInfo.drac 617 */ 618 void determineTTCandDRAC(EncounterApproachInfo& eInfo) const; 619 620 621 /** @brief Computes the time to collision (in seconds) for two vehicles with a given initial gap under the assumption 622 * that both maintain their current speeds. Returns INVALID if no collision would occur under this assumption. 623 */ 624 double computeTTC(double gap, double followerSpeed, double leaderSpeed) const; 625 626 627 /** @brief Computes the DRAC (deceleration to avoid a collision) for a lead/follow situation as defined, 628 * e.g., in Guido et al. (2011, Safety performance measures: a comparison between microsimulation and observational data) 629 * for two vehicles with a given gap. 630 * Returns 0.0 if no deceleration is required by the follower to avoid a crash, INVALID if collision is detected. 631 */ 632 static double computeDRAC(double gap, double followerSpeed, double leaderSpeed); 633 634 /** @brief Computes the DRAC a crossing situation, determining the minimal constant deceleration needed 635 * for one of the vehicles to reach the conflict area after the other has left. 636 * for estimated leaving times, current deceleration is extrapolated, and acceleration is neglected. 637 * Returns 0.0 if no deceleration is required by the follower to avoid a crash, INVALID if collision is detected. 638 * @param[in] eInfo infos on the encounter. Used variables: 639 * dEntry1,dEntry2 The distances to the conflict area entry 640 * dExit1,dExit2 The distances to the conflict area exit 641 * v1,v2 The current speeds 642 * tEntry1,tEntry2 The estimated conflict entry times (including extrapolation of current acceleration) 643 * tExit1,tExit2 The estimated conflict exit times (including extrapolation of current acceleration) 644 */ 645 static double computeDRAC(const EncounterApproachInfo& eInfo); 646 647 /** @brief make a string of a double vector and treat a special value as invalid ("NA") 648 * 649 * @param v vector to be converted to string 650 * @param NA value to be treated as NA 651 * @param sep separator for values in string 652 * @return String concatenation of the vector entries 653 */ 654 static std::string makeStringWithNAs(std::vector<double> v, double NA, std::string sep = " "); 655 static std::string makeStringWithNAs(std::vector<double> v, std::vector<double> NAs, std::string sep = " "); 656 657 /// @name parameter load helpers (introduced for readability of buildVehicleDevices()) 658 /// @{ 659 static std::string getOutputFilename(const SUMOVehicle& v, std::string deviceID); 660 static double getDetectionRange(const SUMOVehicle& v); 661 static double getExtraTime(const SUMOVehicle& v); 662 static bool useGeoCoords(const SUMOVehicle& v); 663 static bool requestsTrajectories(const SUMOVehicle& v); 664 static bool getMeasuresAndThresholds(const SUMOVehicle& v, std::string deviceID, 665 std::map<std::string, double>& thresholds); 666 ///@} 667 668 private: 669 /// @name Device parameters 670 /// @{ 671 /// @brief thresholds for the ssms, i.e., critical values above or below which a value indicates that a conflict 672 /// has occurred. These are used in qualifiesAsConflict() and decide whether an encounter is saved. 673 std::map<std::string, double> myThresholds; 674 /// @brief This determines whether the whole trajectories of the vehicles (position, speed, ssms) shall be saved in the ssm-output 675 /// or only the most critical value shall be reported. 676 bool mySaveTrajectories; 677 /// Detection range. For vehicles closer than this distance from the ego vehicle, SSMs are traced 678 double myRange; 679 /// Extra time in seconds to be logged after a conflict is over 680 double myExtraTime; 681 /// Whether to use the original coordinate system for output 682 bool myUseGeoCoords; 683 /// Flags for switching on / off comutation of different SSMs, derived from myMeasures 684 bool myComputeTTC, myComputeDRAC, myComputePET, myComputeBR, myComputeSGAP, myComputeTGAP; 685 MSVehicle* myHolderMS; 686 /// @} 687 688 689 /// @name Internal storage for encounters/conflicts 690 /// @{ 691 /// @brief Currently observed encounters/conflicts 692 EncounterVector myActiveEncounters; 693 /// @brief begin time of the oldest active encounter 694 double myOldestActiveEncounterBegin; 695 /// @brief Past encounters that where qualified as conflicts and are not yet flushed to the output file 696 EncounterQueue myPastConflicts; 697 /// @} 698 699 700 701 /// @name Internal storage for global measures 702 /// @{ 703 std::vector<double> myGlobalMeasuresTimeSpan; 704 /// @brief All values for brake rate 705 std::vector<double> myBRspan; 706 /// @brief All values for space gap 707 std::vector<double> mySGAPspan; 708 /// @brief All values for time gap 709 std::vector<double> myTGAPspan; 710 /// @brief Extremal values for the global measures (as <<<time, Position>, value>, [leaderID]>-pairs) 711 /// @{ 712 std::pair<std::pair<double, Position>, double> myMaxBR; 713 std::pair<std::pair<std::pair<double, Position>, double>, std::string> myMinSGAP; 714 std::pair<std::pair<std::pair<double, Position>, double>, std::string> myMinTGAP; 715 /// @} 716 /// @} 717 718 /// Output device 719 OutputDevice* myOutputFile; 720 721 /// @brief remember which files were created already (don't duplicate xml root-elements) 722 static std::set<std::string> createdOutputFiles; 723 724 725 /// @brief bitset storing info whether warning has already been issued about unset parameter (warn only once!) 726 static int issuedParameterWarnFlags; 727 enum SSMParameterWarning { 728 SSM_WARN_MEASURES = 1, 729 SSM_WARN_THRESHOLDS = 1 << 1, 730 SSM_WARN_TRAJECTORIES = 1 << 2, 731 SSM_WARN_RANGE = 1 << 3, 732 SSM_WARN_EXTRATIME = 1 << 4, 733 SSM_WARN_FILE = 1 << 5, 734 SSM_WARN_GEO = 1 << 6 735 }; 736 737 738 739 private: 740 /// @brief Invalidated copy constructor. 741 MSDevice_SSM(const MSDevice_SSM&); 742 743 /// @brief Invalidated assignment operator. 744 MSDevice_SSM& operator=(const MSDevice_SSM&); 745 746 747 }; 748 749 #endif 750 751 /****************************************************************************/ 752 753