LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDevice_SSM.h (source / functions) Coverage Total Hit
Test: lcov.info Lines: 30.6 % 36 11
Test Date: 2025-12-06 15:35:27 Functions: 50.0 % 4 2

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

Generated by: LCOV version 2.0-1