LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDevice_SSM.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 13 38 34.2 %
Date: 2024-04-29 15:38:36 Functions: 2 4 50.0 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2013-2024 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      667320 :         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      667320 :             ConflictPointInfo(double time, Position x, EncounterType type, double ssmValue, double speed) :
     203      667320 :                 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        2536 :                 if (e1->begin == e2->begin) {
     234          99 :                     return e1->foeID > e2->foeID;
     235             :                 } else {
     236        2437 :                     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     6611600 :     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     7958464 :     struct FoeInfo {
     341     7958464 :         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     2882849 :         UpstreamScanStartInfo(const MSEdge* edge, double pos, double range, double egoDistToConflictLane, const MSLane* egoConflictLane) :
     357     2882849 :             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        2880 :     const std::string deviceName() const {
     496        2880 :         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             :     /// Whether to exclude certain conflicts containing certain conflict types from the output
     754             :     bool myFilterConflictTypes;
     755             :     /// Which conflict types to exclude from the output
     756             :     std::vector<int> myDroppedConflictTypes;
     757             : 
     758             :     /// Flags for switching on / off comutation of different SSMs, derived from myMeasures
     759             :     bool myComputeTTC, myComputeDRAC, myComputePET, myComputeBR, myComputeSGAP, myComputeTGAP, myComputePPET, myComputeMDRAC;
     760             :     MSVehicle* myHolderMS;
     761             :     /// @}
     762             : 
     763             : 
     764             :     /// @name Internal storage for encounters/conflicts
     765             :     /// @{
     766             :     /// @brief Currently observed encounters/conflicts
     767             :     EncounterVector myActiveEncounters;
     768             :     /// @brief begin time of the oldest active encounter
     769             :     double myOldestActiveEncounterBegin;
     770             :     /// @brief Past encounters that where qualified as conflicts and are not yet flushed to the output file
     771             :     EncounterQueue myPastConflicts;
     772             :     /// @}
     773             : 
     774             : 
     775             : 
     776             :     /// @name Internal storage for global measures
     777             :     /// @{
     778             :     std::vector<double> myGlobalMeasuresTimeSpan;
     779             :     /// @brief All values for positions (coordinates)
     780             :     PositionVector myGlobalMeasuresPositions;
     781             :     /// @brief All values for lanes
     782             :     std::vector<std::string> myGlobalMeasuresLaneIDs;
     783             :     /// @brief All values for positions on the lanes
     784             :     std::vector<double> myGlobalMeasuresLanesPositions;
     785             :     /// @brief All values for brake rate
     786             :     std::vector<double> myBRspan;
     787             :     /// @brief All values for space gap
     788             :     std::vector<double> mySGAPspan;
     789             :     /// @brief All values for time gap
     790             :     std::vector<double> myTGAPspan;
     791             :     /// @brief Extremal values for the global measures (as <<<time, Position>, value>, [leaderID]>-pairs)
     792             :     /// @{
     793             :     std::pair<std::pair<double, Position>, double> myMaxBR;
     794             :     std::pair<std::pair<std::pair<double, Position>, double>, std::string>  myMinSGAP;
     795             :     std::pair<std::pair<std::pair<double, Position>, double>, std::string>  myMinTGAP;
     796             :     /// @}
     797             :     /// @}
     798             : 
     799             :     /// @brief spatial filter for SSM device output
     800             :     static std::set<const MSEdge*> myEdgeFilter;
     801             :     static bool myEdgeFilterInitialized;
     802             :     static bool myEdgeFilterActive;
     803             : 
     804             :     /// Output device
     805             :     OutputDevice* myOutputFile;
     806             : 
     807             :     /// @brief remember which files were created already (don't duplicate xml root-elements)
     808             :     static std::set<std::string> myCreatedOutputFiles;
     809             : 
     810             : 
     811             :     /// @brief bitset storing info whether warning has already been issued about unset parameter (warn only once!)
     812             :     static int myIssuedParameterWarnFlags;
     813             :     enum SSMParameterWarning {
     814             :         SSM_WARN_MEASURES = 1,
     815             :         SSM_WARN_THRESHOLDS = 1 << 1,
     816             :         SSM_WARN_TRAJECTORIES = 1 << 2,
     817             :         SSM_WARN_RANGE = 1 << 3,
     818             :         SSM_WARN_MDRAC_PRT = 1 << 3,
     819             :         SSM_WARN_EXTRATIME = 1 << 4,
     820             :         SSM_WARN_FILE = 1 << 5,
     821             :         SSM_WARN_GEO = 1 << 6,
     822             :         SSM_WARN_POS = 1 << 7,
     823             :         SSM_WARN_LANEPOS = 1 << 8,
     824             :         SSM_WARN_CONFLICTFILTER = 1 << 9
     825             :     };
     826             : 
     827             :     static const std::set<int> FOE_ENCOUNTERTYPES;
     828             :     static const std::set<int> EGO_ENCOUNTERTYPES;
     829             : 
     830             : private:
     831             :     /// @brief Invalidated copy constructor.
     832             :     MSDevice_SSM(const MSDevice_SSM&);
     833             : 
     834             :     /// @brief Invalidated assignment operator.
     835             :     MSDevice_SSM& operator=(const MSDevice_SSM&);
     836             : 
     837             : 
     838             : };

Generated by: LCOV version 1.14