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