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