Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/mesosim/MESegment.h
169666 views
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
class Queue {
73
public:
74
Queue(const SVCPermissions permissions) : myPermissions(permissions) {}
75
inline int size() const {
76
return (int)myVehicles.size();
77
}
78
inline const std::vector<MEVehicle*>& getVehicles() const {
79
return myVehicles;
80
}
81
MEVehicle* remove(MEVehicle* v);
82
inline std::vector<MEVehicle*>& getModifiableVehicles() {
83
return myVehicles;
84
}
85
inline double getOccupancy() const {
86
return myOccupancy;
87
}
88
inline void setOccupancy(const double occ) {
89
myOccupancy = occ;
90
}
91
inline bool allows(SUMOVehicleClass vclass) const {
92
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
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
myEntryBlockTime = entryBlockTime;
103
}
104
105
inline SUMOTime getBlockTime() const {
106
return myBlockTime;
107
}
108
inline void setBlockTime(SUMOTime t) {
109
myBlockTime = t;
110
}
111
112
inline void setPermissions(SVCPermissions p) {
113
myPermissions = p;
114
}
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
inline int getCarNumber() const {
209
return myNumVehicles;
210
}
211
212
/// @brief return the number of queues
213
inline int numQueues() const {
214
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
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
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
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
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
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
for (const Queue& q : myQueues) {
263
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
inline double getRelativeOccupancy() const {
272
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
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
inline double getMeanSpeed() const {
300
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
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
inline double getEventTimeSeconds() const {
382
return STEPS2TIME(getEventTime());
383
}
384
385
/// @brief get the last headway time in seconds
386
inline double getLastHeadwaySeconds() const {
387
return STEPS2TIME(myLastHeadway);
388
}
389
390
/// @brief get the earliest entry time in seconds
391
inline double getEntryBlockTimeSeconds() const {
392
SUMOTime t = SUMOTime_MAX;
393
for (const Queue& q : myQueues) {
394
t = MIN2(t, q.getEntryBlockTime());
395
}
396
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
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
for (const Queue& q : myQueues) {
458
if (q.getOccupancy() == 0. && myQueueCapacity < vehLength) {
459
// even small segments can hold at least one vehicle
460
cap += 1;
461
} else {
462
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
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
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
};
598
599