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 : };
|