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