Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MESegment.h
15 : /// @author Daniel Krajzewicz
16 : /// @date Tue, May 2005
17 : ///
18 : // A single mesoscopic segment (cell)
19 : /****************************************************************************/
20 : #pragma once
21 : #include <config.h>
22 :
23 : #include <vector>
24 : #include <cassert>
25 : #include <utils/common/SUMOVehicleClass.h>
26 : #include <utils/common/Named.h>
27 : #include <utils/common/SUMOTime.h>
28 : #include <microsim/MSMoveReminder.h>
29 :
30 :
31 : // ===========================================================================
32 : // class declarations
33 : // ===========================================================================
34 : class SUMOVehicle;
35 : class MSEdge;
36 : class MSLink;
37 : class MSDetectorFileOutput;
38 : class MSVehicleControl;
39 : class MEVehicle;
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 : static const double DO_NOT_PATCH_JAM_THRESHOLD;
53 : static const int PARKING_QUEUE = -1;
54 : static const std::string OVERRIDE_TLS_PENALTIES;
55 :
56 : /// @brief edge type specific meso parameters
57 : struct MesoEdgeType {
58 : SUMOTime tauff;
59 : SUMOTime taufj;
60 : SUMOTime taujf;
61 : SUMOTime taujj;
62 : double jamThreshold;
63 : bool junctionControl;
64 : double tlsPenalty;
65 : double tlsFlowPenalty;
66 : SUMOTime minorPenalty;
67 : bool overtaking;
68 : };
69 :
70 :
71 : private:
72 1981824 : class Queue {
73 : public:
74 654289 : Queue(const SVCPermissions permissions) : myPermissions(permissions) {}
75 : inline int size() const {
76 111764169 : return (int)myVehicles.size();
77 : }
78 : inline const std::vector<MEVehicle*>& getVehicles() const {
79 663580 : return myVehicles;
80 : }
81 : MEVehicle* remove(MEVehicle* v);
82 : inline std::vector<MEVehicle*>& getModifiableVehicles() {
83 24070650 : return myVehicles;
84 : }
85 : inline double getOccupancy() const {
86 130235069 : return myOccupancy;
87 : }
88 : inline void setOccupancy(const double occ) {
89 24065147 : myOccupancy = occ;
90 : }
91 : inline bool allows(SUMOVehicleClass vclass) const {
92 40714012 : return (myPermissions & vclass) == vclass;
93 : }
94 :
95 : /// @brief return the next time at which a vehicle may enter this queue
96 : inline SUMOTime getEntryBlockTime() const {
97 17957680 : return myEntryBlockTime;
98 : }
99 :
100 : /// @brief set the next time at which a vehicle may enter this queue
101 : inline void setEntryBlockTime(SUMOTime entryBlockTime) {
102 23368880 : myEntryBlockTime = entryBlockTime;
103 23368295 : }
104 :
105 : inline SUMOTime getBlockTime() const {
106 65073285 : return myBlockTime;
107 : }
108 : inline void setBlockTime(SUMOTime t) {
109 585 : myBlockTime = t;
110 23383737 : }
111 :
112 : inline void setPermissions(SVCPermissions p) {
113 48 : myPermissions = p;
114 1808 : }
115 :
116 : void addDetector(MSMoveReminder* data);
117 :
118 : void addReminders(MEVehicle* veh) const;
119 :
120 : private:
121 : /// The vClass permissions for this queue
122 : SVCPermissions myPermissions;
123 :
124 : std::vector<MEVehicle*> myVehicles;
125 :
126 : /// @brief The occupied space (in m) in the queue
127 : double myOccupancy = 0.;
128 :
129 : /// @brief The block time for vehicles who wish to enter this queue
130 : SUMOTime myEntryBlockTime = SUMOTime_MIN;
131 :
132 : /// @brief The block time
133 : SUMOTime myBlockTime = -1;
134 :
135 : /// @brief The data collection for all kinds of detectors
136 : std::vector<MSMoveReminder*> myDetectorData;
137 :
138 : };
139 :
140 : public:
141 : /** @brief constructor
142 : * @param[in] id The id of this segment (currently: "<EDGEID>:<SEGMENTNO>")
143 : * @param[in] parent The edge this segment is located within
144 : * @param[in] next The following segment (belonging to the same edge)
145 : * @param[in] length The segment's length
146 : * @param[in] speed The speed allowed on this segment
147 : * @param[in] idx The running index of this segment within the segment's edge
148 : * @param[in] multiQueue whether to install multiple queues on this segment
149 : * @param[in] edgeType edge type specific meso parameters such as the different taus
150 : */
151 : MESegment(const std::string& id,
152 : const MSEdge& parent, MESegment* next,
153 : const double length, const double speed,
154 : const int idx,
155 : const bool multiQueue,
156 : const MesoEdgeType& edgeType);
157 :
158 : /// @brief set model parameters (may be updated from additional file after network loading is complete)
159 : void initSegment(const MesoEdgeType& edgeType, const MSEdge& parent, const double capacity);
160 :
161 : /// @name Measure collection
162 : /// @{
163 :
164 : /** @brief Adds a data collector for a detector to this segment
165 : *
166 : * @param[in] data The data collector to add
167 : * @param[in] queueIndex The queue (aka lane) to use, -1 means all
168 : */
169 : void addDetector(MSMoveReminder* data, int queueIndex = -1);
170 :
171 : /** @brief Removes a data collector for a detector from this segment
172 : *
173 : * @param[in] data The data collector to remove
174 : * @note: currently not used
175 : */
176 : // void removeDetector(MSMoveReminder* data);
177 :
178 : /** @brief Updates data of a detector for one or all vehicle queues
179 : *
180 : * @param[in] data The detector data to update
181 : * @param[in] queueIndex The queue (aka lane) to use, -1 means all
182 : */
183 : void prepareDetectorForWriting(MSMoveReminder& data, int queueIndex = -1);
184 : /// @}
185 :
186 : /** @brief Returns whether the given vehicle would still fit into the segment
187 : *
188 : * @param[in] veh The vehicle to check space for
189 : * @param[in] entryTime The time at which the vehicle wants to enter
190 : * @param[out] qIdx The index of the queue the vehicle should choose
191 : * @param[in] init whether the check is done at insertion time
192 : * @return the earliest time a vehicle may be added to this segment
193 : */
194 : SUMOTime hasSpaceFor(const MEVehicle* const veh, const SUMOTime entryTime, int& qIdx, const bool init = false) const;
195 :
196 : /** @brief Inserts (emits) vehicle into the segment
197 : *
198 : * @param[in] veh The vehicle to emit
199 : * @param[in] time The emission time
200 : * @return Whether the emission was successful
201 : */
202 : bool initialise(MEVehicle* veh, SUMOTime time);
203 :
204 : /** @brief Returns the total number of cars on the segment
205 : *
206 : * @return the total number of cars on the segment
207 : */
208 0 : inline int getCarNumber() const {
209 140354015 : return myNumVehicles;
210 : }
211 :
212 : /// @brief return the number of queues
213 : inline int numQueues() const {
214 987288 : return (int)myQueues.size();
215 : }
216 : /** @brief Returns the cars in the queue with the given index for visualization
217 : * @return the Queue (XXX not thread-safe!)
218 : */
219 : inline const std::vector<MEVehicle*>& getQueue(int index) const {
220 : assert(index < (int)myQueues.size());
221 662830 : return myQueues[index].getVehicles();
222 : }
223 :
224 : /** @brief Returns the running index of the segment in the edge (0 is the most upstream).
225 : *
226 : * @return the running index of the segment in the edge
227 : */
228 : inline int getIndex() const {
229 8127713 : return myIndex;
230 : }
231 :
232 : /** @brief Returns the following segment on the same edge (0 if it is the last).
233 : *
234 : * @return the following segment on the same edge (0 if it is the last)
235 : */
236 : inline MESegment* getNextSegment() const {
237 206931651 : return myNextSegment;
238 : }
239 :
240 : /** @brief Returns the length of the segment in meters.
241 : *
242 : * @return the length of the segment
243 : */
244 : inline double getLength() const {
245 108584717 : return myLength;
246 : }
247 :
248 : /** @brief Returns the sum of the lengths of all usable lanes of the segment in meters.
249 : *
250 : * @return the capacity of the segment
251 : */
252 : inline double getCapacity() const {
253 1078 : return myCapacity;
254 : }
255 :
256 : /** @brief Returns the occupany of the segment (the sum of the vehicle lengths + minGaps)
257 : *
258 : * @return the occupany of the segment in meters
259 : */
260 : inline double getBruttoOccupancy() const {
261 : double occ = 0.;
262 363882 : for (const Queue& q : myQueues) {
263 182834 : occ += q.getOccupancy();
264 : }
265 : return occ;
266 : }
267 :
268 : /** @brief Returns the relative occupany of the segment (percentage of road used))
269 : * @return the occupany of the segment in percent
270 : */
271 0 : inline double getRelativeOccupancy() const {
272 0 : return getBruttoOccupancy() / myCapacity;
273 : }
274 :
275 : /** @brief Returns the relative occupany of the segment (percentage of road used))
276 : * at which the segment is considered jammed
277 : * @return the jam threshold of the segment in percent
278 : */
279 : inline double getRelativeJamThreshold() const {
280 0 : return myJamThreshold / myCapacity;
281 : }
282 :
283 : /** @brief Returns the average speed of vehicles on the segment in meters per second.
284 : * If there is no vehicle on the segment it returns the maximum allowed speed
285 : * @param[in] useCache whether to use a cached value if available
286 : * @note this value is cached in myMeanSpeed. Since caching only takes place
287 : * once every simstep there is a potential for side-influences (i.e. GUI calls to
288 : * this method, ...) For that reason the simulation logic doesn't use the cache.
289 : * This shouldn't matter much for speed since it is only used during
290 : * initializsation of vehicles onto the segment.
291 : * @return the average speed on the segment
292 : */
293 : double getMeanSpeed(bool useCache) const;
294 :
295 : /// @brief reset myLastMeanSpeedUpdate
296 : void resetCachedSpeeds();
297 :
298 : /// @brief wrapper to satisfy the FunctionBinding signature
299 0 : inline double getMeanSpeed() const {
300 24042765 : return getMeanSpeed(true);
301 : }
302 :
303 :
304 : void writeVehicles(OutputDevice& of) const;
305 :
306 : /** @brief Removes the given car from the edge's que
307 : *
308 : * @param[in] v The vehicle to remove
309 : * @param[in] leaveTime The time at which the vehicle is leaving the que
310 : * @param[in] reason The reason for removing to send to reminders
311 : * @return The next first vehicle to add to the net's que
312 : */
313 : MEVehicle* removeCar(MEVehicle* v, SUMOTime leaveTime, const MSMoveReminder::Notification reason);
314 :
315 : /** @brief Returns the link the given car will use when passing the next junction
316 : *
317 : * This returns non-zero values only for the last segment and only
318 : * if junction control is enabled.
319 : *
320 : * @param[in] veh The vehicle in question
321 : * @param[in] tlsPenalty Whether the link should be returned for computing tlsPenalty
322 : * @return The link to use or 0 without junction control
323 : */
324 : MSLink* getLink(const MEVehicle* veh, bool tlsPenalty = false) const;
325 :
326 : /** @brief Returns whether the vehicle may use the next link
327 : *
328 : * In case of disabled junction control it returns always true.
329 : *
330 : * @param[in] veh The vehicle in question
331 : * @return Whether it may pass to the next segment
332 : */
333 : bool isOpen(const MEVehicle* veh) const;
334 :
335 : /** @brief Removes the vehicle from the segment, adapting its parameters
336 : *
337 : * @param[in] veh The vehicle in question
338 : * @param[in] next The subsequent segment for delay calculation
339 : * @param[in] time the leave time
340 : * @todo Isn't always time == veh->getEventTime?
341 : */
342 : void send(MEVehicle* veh, MESegment* const next, const int nextQIdx, SUMOTime time, const MSMoveReminder::Notification reason);
343 :
344 : /** @brief Adds the vehicle to the segment, adapting its parameters
345 : *
346 : * @param[in] veh The vehicle in question
347 : * @param[in] time the leave time
348 : * @param[in] isDepart whether the vehicle just departed
349 : * @todo Isn't always time == veh->getEventTime?
350 : */
351 : void receive(MEVehicle* veh, const int qIdx, SUMOTime time, const bool isDepart = false, const bool isTeleport = false, const bool newEdge = false);
352 :
353 :
354 : /** @brief tries to remove any car from this segment
355 : *
356 : * @param[in] currentTime the current time
357 : * @return Whether vaporization was successful
358 : * @note: cars removed via this method do NOT count as arrivals */
359 : bool vaporizeAnyCar(SUMOTime currentTime, const MSDetectorFileOutput* filter);
360 :
361 : /** @brief Returns the edge this segment belongs to
362 : * @return the edge this segment belongs to
363 : */
364 : inline const MSEdge& getEdge() const {
365 75423158 : return myEdge;
366 : }
367 :
368 :
369 : /** @brief reset mySpeed and patch the speed of
370 : * all vehicles in it. Also set/recompute myJamThreshold
371 : * @param[in] jamThresh follows the semantic of option meso-jam-threshold
372 : */
373 : void setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh = DO_NOT_PATCH_JAM_THRESHOLD, int qIdx = -1);
374 :
375 : /** @brief Returns the (planned) time at which the next vehicle leaves this segment
376 : * @return The time the vehicle thinks it leaves
377 : */
378 : SUMOTime getEventTime() const;
379 :
380 : /// @brief Like getEventTime but returns seconds (for visualization)
381 0 : inline double getEventTimeSeconds() const {
382 0 : return STEPS2TIME(getEventTime());
383 : }
384 :
385 : /// @brief get the last headway time in seconds
386 0 : inline double getLastHeadwaySeconds() const {
387 0 : return STEPS2TIME(myLastHeadway);
388 : }
389 :
390 : /// @brief get the earliest entry time in seconds
391 0 : inline double getEntryBlockTimeSeconds() const {
392 : SUMOTime t = SUMOTime_MAX;
393 0 : for (const Queue& q : myQueues) {
394 : t = MIN2(t, q.getEntryBlockTime());
395 : }
396 0 : return STEPS2TIME(t);
397 : }
398 :
399 : /// @brief Get the waiting time for vehicles in all queues
400 : double getWaitingSeconds() const;
401 :
402 : /// @name State saving/loading
403 : /// @{
404 :
405 : /** @brief Saves the state of this segment into the given stream
406 : *
407 : * Some internal values which must be restored are saved as well as ids of
408 : * the vehicles stored in internal queues and the last departures of connected
409 : * edges.
410 : *
411 : * @param[in, filled] out The (possibly binary) device to write the state into
412 : * @todo What about throwing an IOError?
413 : */
414 : void saveState(OutputDevice& out) const;
415 :
416 : /** @brief Remove all vehicles before quick-loading state */
417 : void clearState();
418 :
419 : /** @brief Loads the state of this segment with the given parameters
420 : *
421 : * This method is called for every internal que the segment has.
422 : * Every vehicle is retrieved from the given MSVehicleControl and added to this
423 : * segment. Then, the internal queues that store vehicles dependant to their next
424 : * edge are filled the same way. Then, the departure of last vehicles onto the next
425 : * edge are restored.
426 : *
427 : * @param[in] vehs The vehicles for the current que
428 : * @param[in] blockTime The time the last vehicle left the que
429 : * @param[in] queIdx The index of the current que
430 : * @todo What about throwing an IOError?
431 : * @todo What about throwing an error if something else fails (a vehicle can not be referenced)?
432 : */
433 : void loadState(const std::vector<SUMOVehicle*>& vehs, const SUMOTime blockTime, const SUMOTime entryBlockTime, const int queIdx);
434 : /// @}
435 :
436 :
437 : /** @brief returns all vehicles (for debugging)
438 : */
439 : std::vector<const MEVehicle*> getVehicles() const;
440 :
441 : /** @brief returns flow based on headway
442 : * @note: returns magic number 10000 when headway cannot be computed
443 : */
444 : double getFlow() const;
445 :
446 : /// @brief whether the given segment is 0 or encodes vaporization
447 : static inline bool isInvalid(const MESegment* segment) {
448 58073515 : return segment == nullptr || segment == &myVaporizationTarget;
449 : }
450 :
451 : /// @brief return a time after earliestEntry at which a vehicle may be inserted at full speed
452 : SUMOTime getNextInsertionTime(SUMOTime earliestEntry) const;
453 :
454 : /// @brief return the remaining physical space on this segment
455 : inline int remainingVehicleCapacity(const double vehLength) const {
456 : int cap = 0;
457 153203 : for (const Queue& q : myQueues) {
458 77062 : if (q.getOccupancy() == 0. && myQueueCapacity < vehLength) {
459 : // even small segments can hold at least one vehicle
460 0 : cap += 1;
461 : } else {
462 77062 : cap += (int)((myQueueCapacity - q.getOccupancy()) / vehLength);
463 : }
464 : }
465 : return cap;
466 : }
467 :
468 : /// @brief return the minimum headway-time with which vehicles may enter or leave this segment
469 : inline SUMOTime getMinimumHeadwayTime() const {
470 76141 : return myTau_ff;
471 : }
472 :
473 : /// @brief add this lanes MoveReminders to the given vehicle
474 : void addReminders(MEVehicle* veh) const;
475 :
476 : /** @brief Returns the penalty time for passing a link (if using gMesoTLSPenalty > 0 or gMesoMinorPenalty > 0)
477 : * @param[in] veh The vehicle in question
478 : * @return The time penalty
479 : */
480 : SUMOTime getLinkPenalty(const MEVehicle* veh) const;
481 :
482 : /// @brief called when permissions change due to Rerouter or TraCI
483 : void updatePermissions();
484 :
485 : private:
486 : bool overtake();
487 :
488 : void setSpeedForQueue(double newSpeed, SUMOTime currentTime,
489 : SUMOTime blockTime, const std::vector<MEVehicle*>& vehs);
490 :
491 : /** @brief compute the new arrival time when switching speed
492 : */
493 : SUMOTime newArrival(const MEVehicle* const v, double newSpeed, SUMOTime currentTime);
494 :
495 : /// @brief whether a leader in any queue is blocked
496 : bool hasBlockedLeader() const;
497 :
498 : /** @brief compute a value for myJamThreshold
499 : * if jamThresh is negative, compute a value which allows free flow at mySpeed
500 : * interpret jamThresh as the relative occupation at which jam starts
501 : */
502 : void recomputeJamThreshold(double jamThresh);
503 :
504 : /// @brief compute jam threshold for the given speed and jam-threshold option
505 : double jamThresholdForSpeed(double speed, double jamThresh) const;
506 :
507 : /// @brief whether the given link may be passed because the option meso-junction-control.limited is set
508 : bool limitedControlOverride(const MSLink* link) const;
509 :
510 : /// @brief convert net time gap (leader back to follower front) to gross time gap (leader front to follower front)
511 : inline SUMOTime tauWithVehLength(SUMOTime tau, double lengthWithGap, double vehicleTau) const {
512 176205147 : return (SUMOTime)((double)tau * vehicleTau + lengthWithGap * myTau_length);
513 : }
514 :
515 : SUMOTime getTauJJ(double nextQueueSize, double nextQueueCapacity, double nextJamThreshold) const;
516 :
517 : /// @brief whether the traffic light should use normal junction control despite penalty options
518 : bool tlsPenaltyOverride() const;
519 :
520 : private:
521 : /// @brief The microsim edge this segment belongs to
522 : const MSEdge& myEdge;
523 :
524 : /// @brief The next segment of this edge, 0 if this is the last segment of this edge
525 : MESegment* myNextSegment;
526 :
527 : /// @brief The segment's length
528 : const double myLength;
529 :
530 : /// @brief Running number of the segment in the edge
531 : const int myIndex;
532 :
533 : /// @name Model constants that may be reset once via additional file
534 : /// @{
535 :
536 : /// @brief The time headway parameters, see the Eissfeldt thesis
537 : SUMOTime myTau_ff, myTau_fj, myTau_jf, myTau_jj;
538 :
539 : /// @brief Whether tls penalty is enabled
540 : bool myTLSPenalty;
541 :
542 : /// @brief penalty for minor links
543 : bool myCheckMinorPenalty; // for legacy compatibility (#7802, 7804)
544 : SUMOTime myMinorPenalty;
545 :
546 : /// @brief Whether junction control is enabled
547 : bool myJunctionControl;
548 :
549 : /// @brief Whether overtaking is permitted on this segment
550 : bool myOvertaking;
551 : /// @}
552 :
553 : /// @brief Headway parameter for computing gross time headyway from net time headway, length and edge speed
554 : double myTau_length;
555 :
556 : /// @brief The number of lanes represented by the queue * the length of the lane
557 : double myCapacity = 0.;
558 :
559 : /// @brief The number of lanes represented by the queue * the length of the lane
560 : double myQueueCapacity = 0.;
561 :
562 : /// @brief The space (in m) which needs to be occupied before the segment is considered jammed
563 : double myJamThreshold;
564 :
565 : /// @brief The car queues. Vehicles are inserted in the front and removed in the back
566 : std::vector<Queue> myQueues;
567 :
568 : /// @brief The cached value for the number of vehicles
569 : int myNumVehicles;
570 :
571 : /// @brief The follower edge to allowed que index mapping for multi queue segments
572 : std::map<const MSEdge*, int> myFollowerMap;
573 :
574 : /// @brief the last headway
575 : SUMOTime myLastHeadway;
576 :
577 : /* @brief segment for signifying vaporization. This segment has invalid
578 : * data and should only be used as a unique pointer */
579 : static MSEdge myDummyParent;
580 : static MESegment myVaporizationTarget;
581 :
582 : /// @brief the mean speed on this segment. Updated at event time or on demand
583 : mutable double myMeanSpeed;
584 :
585 : /// @brief the time at which myMeanSpeed was last updated
586 : mutable SUMOTime myLastMeanSpeedUpdate;
587 :
588 : private:
589 : /// @brief Invalidated copy constructor.
590 : MESegment(const MESegment&);
591 :
592 : /// @brief Invalidated assignment operator.
593 : MESegment& operator=(const MESegment&);
594 :
595 : /// @brief constructor for dummy segment
596 : MESegment(const std::string& id);
597 : };
|