Eclipse SUMO - Simulation of Urban MObility
MESegment.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3// Copyright (C) 2001-2022 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/****************************************************************************/
18// A single mesoscopic segment (cell)
19/****************************************************************************/
20#include <config.h>
21
22#include <algorithm>
23#include <limits>
25#include <microsim/MSGlobals.h>
26#include <microsim/MSEdge.h>
27#include <microsim/MSJunction.h>
28#include <microsim/MSNet.h>
29#include <microsim/MSLane.h>
30#include <microsim/MSLink.h>
39#include "MEVehicle.h"
40#include "MELoop.h"
41#include "MESegment.h"
42
43#define DEFAULT_VEH_LENGTH_WITH_GAP (SUMOVTypeParameter::getDefault().length + SUMOVTypeParameter::getDefault().minGap)
44// avoid division by zero when driving very slowly
45#define MESO_MIN_SPEED (0.05)
46
47//#define DEBUG_OPENED
48//#define DEBUG_JAMTHRESHOLD
49//#define DEBUG_COND (getID() == "blocker")
50//#define DEBUG_COND (true)
51#define DEBUG_COND (myEdge.isSelected())
52#define DEBUG_COND2(obj) ((obj != 0 && (obj)->isSelected()))
53
54
55// ===========================================================================
56// static member defintion
57// ===========================================================================
58MSEdge MESegment::myDummyParent("MESegmentDummyParent", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", -1, 0);
59MESegment MESegment::myVaporizationTarget("vaporizationTarget");
60const double MESegment::DO_NOT_PATCH_JAM_THRESHOLD(std::numeric_limits<double>::max());
61
62
63// ===========================================================================
64// MESegment::Queue method definitions
65// ===========================================================================
69 assert(std::find(myVehicles.begin(), myVehicles.end(), v) != myVehicles.end());
70 if (v == myVehicles.back()) {
71 myVehicles.pop_back();
72 if (myVehicles.empty()) {
73 myOccupancy = 0.;
74 } else {
75 return myVehicles.back();
76 }
77 } else {
78 myVehicles.erase(std::find(myVehicles.begin(), myVehicles.end(), v));
79 }
80 return nullptr;
81}
82
83
84// ===========================================================================
85// MESegment method definitions
86// ===========================================================================
87MESegment::MESegment(const std::string& id,
88 const MSEdge& parent, MESegment* next,
89 const double length, const double speed,
90 const int idx,
91 const bool multiQueue,
92 const MesoEdgeType& edgeType):
93 Named(id), myEdge(parent), myNextSegment(next),
94 myLength(length), myIndex(idx),
98 myMeanSpeed(speed),
100
101 const std::vector<MSLane*>& lanes = parent.getLanes();
102 int usableLanes = 0;
103 for (MSLane* const l : lanes) {
104 const SVCPermissions allow = MSEdge::getMesoPermissions(l->getPermissions());
105 if (multiQueue) {
106 myQueues.push_back(Queue(allow));
107 }
108 if (allow != 0) {
109 usableLanes++;
110 }
111 }
112 if (multiQueue) {
113 if (next == nullptr) {
114 for (const MSEdge* const edge : parent.getSuccessors()) {
115 const std::vector<MSLane*>* const allowed = parent.allowedLanes(*edge);
116 assert(allowed != nullptr);
117 assert(allowed->size() > 0);
118 for (MSLane* const l : *allowed) {
119 std::vector<MSLane*>::const_iterator it = std::find(lanes.begin(), lanes.end(), l);
120 myFollowerMap[edge] |= (1 << distance(lanes.begin(), it));
121 }
122 }
123 }
124 myQueueCapacity = length;
125 } else {
126 myQueues.push_back(Queue(parent.getPermissions()));
127 }
128
129 initSegment(edgeType, parent, length * usableLanes);
130}
131
132void
133MESegment::initSegment(const MesoEdgeType& edgeType, const MSEdge& parent, const double capacity) {
134
135 myCapacity = capacity;
136 if (myQueues.size() == 1) {
137 const double laneScale = capacity / myLength;
138 myQueueCapacity = capacity;
140 // Eissfeldt p. 90 and 151 ff.
141 myTau_ff = (SUMOTime)((double)edgeType.tauff / laneScale);
142 myTau_fj = (SUMOTime)((double)edgeType.taufj / laneScale);
143 myTau_jf = (SUMOTime)((double)edgeType.taujf / laneScale);
144 myTau_jj = (SUMOTime)((double)edgeType.taujj / laneScale);
145 } else {
146 myTau_ff = edgeType.tauff;
147 myTau_fj = edgeType.taufj;
148 myTau_jf = edgeType.taujf;
149 myTau_jj = edgeType.taujj;
150 }
151
153 myTLSPenalty = ((edgeType.tlsPenalty > 0 || edgeType.tlsFlowPenalty > 0) &&
154 // only apply to the last segment of a tls-controlled edge
155 myNextSegment == nullptr && (
159
160 // only apply to the last segment of an uncontrolled edge that has at least 1 minor link
161 myCheckMinorPenalty = (edgeType.minorPenalty > 0 &&
162 myNextSegment == nullptr &&
166 parent.hasMinorLink());
167 myMinorPenalty = edgeType.minorPenalty;
169
170 //std::cout << getID() << " myMinorPenalty=" << myMinorPenalty << " myTLSPenalty=" << myTLSPenalty << " myJunctionControl=" << myJunctionControl << " myOvertaking=" << myOvertaking << "\n";
171
173}
174
175MESegment::MESegment(const std::string& id):
176 Named(id),
177 myEdge(myDummyParent), // arbitrary edge needed to supply the needed reference
178 myNextSegment(nullptr), myLength(0), myIndex(0),
179 myTau_ff(0), myTau_fj(0), myTau_jf(0), myTau_jj(0),
180 myTLSPenalty(false),
181 myCheckMinorPenalty(false),
182 myMinorPenalty(0),
183 myJunctionControl(false),
184 myOvertaking(false),
185 myTau_length(1) {
186}
187
188
189void
191 if (myQueues.size() > 1) {
192 for (MSLane* lane : myEdge.getLanes()) {
193 myQueues[lane->getIndex()].setPermissions(lane->getPermissions());
194 }
195 } else {
196 myQueues.back().setPermissions(myEdge.getPermissions());
197 }
198}
199
200
201void
203 if (jamThresh == DO_NOT_PATCH_JAM_THRESHOLD) {
204 return;
205 }
206 if (jamThresh < 0) {
207 // compute based on speed
209 } else {
210 // compute based on specified percentage
211 myJamThreshold = jamThresh * myCapacity;
212 }
213}
214
215
216double
217MESegment::jamThresholdForSpeed(double speed, double jamThresh) const {
218 // vehicles driving freely at maximum speed should not jam
219 // we compute how many vehicles could possible enter the segment until the first vehicle leaves
220 // and multiply by the space these vehicles would occupy
221 // the jamThresh parameter is scale the resulting value
222 if (speed == 0) {
223 return std::numeric_limits<double>::max(); // never jam. Irrelevant at speed 0 anyway
224 }
225#ifdef DEBUG_JAMTHRESHOLD
226 if (true || DEBUG_COND) {
227 std::cout << "jamThresholdForSpeed seg=" << getID() << " speed=" << speed << " jamThresh=" << jamThresh << " ffVehs=" << std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGTH_WITH_GAP)))) << " thresh=" << std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGTH_WITH_GAP)))) * DEFAULT_VEH_LENGTH_WITH_GAP
228 << "\n";
229 }
230#endif
232}
233
234
235void
237 myDetectorData.push_back(data);
238 for (const Queue& q : myQueues) {
239 for (MEVehicle* const v : q.getVehicles()) {
240 v->addReminder(data);
241 }
242 }
243}
244
245
246void
248 std::vector<MSMoveReminder*>::iterator it = std::find(myDetectorData.begin(), myDetectorData.end(), data);
249 if (it != myDetectorData.end()) {
250 myDetectorData.erase(it);
251 }
252 for (const Queue& q : myQueues) {
253 for (MEVehicle* const v : q.getVehicles()) {
254 v->removeReminder(data);
255 }
256 }
257}
258
259
260void
262 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
263 for (const Queue& q : myQueues) {
264 SUMOTime earliestExitTime = currentTime;
265 for (std::vector<MEVehicle*>::const_reverse_iterator i = q.getVehicles().rbegin(); i != q.getVehicles().rend(); ++i) {
266 const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
267 (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
268 earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
269 }
270 }
271}
272
273
275MESegment::hasSpaceFor(const MEVehicle* const veh, const SUMOTime entryTime, int& qIdx, const bool init) const {
276 SUMOTime earliestEntry = SUMOTime_MAX;
277 qIdx = 0;
278 if (myNumVehicles == 0 && myQueues.size() == 1) {
279 // we have always space for at least one vehicle
280 if (myQueues.front().allows(veh->getVClass())) {
281 return entryTime;
282 } else {
283 return earliestEntry;
284 }
285 }
286 const SUMOVehicleClass svc = veh->getVClass();
287 int minSize = std::numeric_limits<int>::max();
288 const MSEdge* const succ = myNextSegment == nullptr ? veh->succEdge(1) : nullptr;
289 for (int i = 0; i < (int)myQueues.size(); i++) {
290 const Queue& q = myQueues[i];
291 const double newOccupancy = q.size() == 0 ? 0. : q.getOccupancy() + veh->getVehicleType().getLengthWithGap();
292 if (newOccupancy <= myQueueCapacity) { // we must ensure that occupancy remains below capacity
293 if (succ == nullptr || myFollowerMap.count(succ) == 0 || ((myFollowerMap.find(succ)->second & (1 << i)) != 0)) {
294 if (q.allows(svc) && q.size() < minSize) {
295 if (init) {
296 // regular insertions and initial insertions must respect different constraints:
297 // - regular insertions must respect entryBlockTime
298 // - initial insertions should not cause additional jamming
299 // - inserted vehicle should be able to continue at the current speed
301 if (newOccupancy <= myJamThreshold) {
302 qIdx = i;
303 minSize = q.size();
304 }
305 } else {
306 if (newOccupancy <= jamThresholdForSpeed(getMeanSpeed(false), -1)) {
307 qIdx = i;
308 minSize = q.size();
309 }
310 }
311 } else if (entryTime >= q.getEntryBlockTime()) {
312 qIdx = i;
313 minSize = q.size();
314 } else {
315 earliestEntry = MIN2(earliestEntry, q.getEntryBlockTime());
316 }
317 }
318 }
319 }
320 }
321 if (minSize == std::numeric_limits<int>::max()) {
322 return earliestEntry;
323 }
324 return entryTime;
325}
326
327
328bool
330 int qIdx = 0;
331 if (hasSpaceFor(veh, time, qIdx, true) == time) {
332 receive(veh, qIdx, time, true);
333 // we can check only after insertion because insertion may change the route via devices
334 std::string msg;
335 if (MSGlobals::gCheckRoutes && !veh->hasValidRoute(msg)) {
336 throw ProcessError("Vehicle '" + veh->getID() + "' has no valid route. " + msg);
337 }
338 return true;
339 }
340 return false;
341}
342
343
344double
345MESegment::getMeanSpeed(bool useCached) const {
346 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
347 if (currentTime != myLastMeanSpeedUpdate || !useCached) {
348 myLastMeanSpeedUpdate = currentTime;
349 double v = 0;
350 int count = 0;
351 for (const Queue& q : myQueues) {
352 const SUMOTime tau = q.getOccupancy() < myJamThreshold ? myTau_ff : myTau_jf;
353 SUMOTime earliestExitTime = currentTime;
354 count += q.size();
355 for (std::vector<MEVehicle*>::const_reverse_iterator veh = q.getVehicles().rbegin(); veh != q.getVehicles().rend(); ++veh) {
356 v += (*veh)->getConservativeSpeed(earliestExitTime); // earliestExitTime is updated!
357 earliestExitTime += tauWithVehLength(tau, (*veh)->getVehicleType().getLengthWithGap(), (*veh)->getVehicleType().getCarFollowModel().getHeadwayTime());
358 }
359 }
360 if (count == 0) {
362 } else {
363 myMeanSpeed = v / (double) count;
364 }
365 }
366 return myMeanSpeed;
367}
368
369
370void
372 for (const Queue& q : myQueues) {
373 for (const MEVehicle* const veh : q.getVehicles()) {
375 }
376 }
377}
378
379
382 Queue& q = myQueues[v->getQueIndex()];
383 // One could be tempted to do v->setSegment(next); here but position on lane will be invalid if next == 0
384 v->updateDetectors(leaveTime, true, reason);
386 myEdge.lock();
387 MEVehicle* nextLeader = q.remove(v);
388 myEdge.unlock();
389 return nextLeader;
390}
391
392
395 // since we do not know which queue will be used we give a conservative estimate
396 SUMOTime earliestLeave = earliestEntry;
397 SUMOTime latestEntry = -1;
398 for (const Queue& q : myQueues) {
399 earliestLeave = MAX2(earliestLeave, q.getBlockTime());
400 latestEntry = MAX2(latestEntry, q.getEntryBlockTime());
401 }
402 if (myEdge.getSpeedLimit() == 0) {
403 return MAX2(earliestEntry, latestEntry); // FIXME: This line is just an adhoc-fix to avoid division by zero (Leo)
404 } else {
405 return MAX3(earliestEntry, earliestLeave - TIME2STEPS(myLength / myEdge.getSpeedLimit()), latestEntry);
406 }
407}
408
409
410MSLink*
411MESegment::getLink(const MEVehicle* veh, bool penalty) const {
412 if (myJunctionControl || penalty) {
413 const MSEdge* const nextEdge = veh->succEdge(1);
414 if (nextEdge == nullptr || veh->getQueIndex() == PARKING_QUEUE) {
415 return nullptr;
416 }
417 // try to find any link leading to our next edge, start with the lane pointed to by the que index
418 const MSLane* const bestLane = myEdge.getLanes()[veh->getQueIndex()];
419 for (MSLink* const link : bestLane->getLinkCont()) {
420 if (&link->getLane()->getEdge() == nextEdge) {
421 return link;
422 }
423 }
424 // this is for the non-multique case, maybe we should use caching here !!!
425 for (const MSLane* const lane : myEdge.getLanes()) {
426 if (lane != bestLane) {
427 for (MSLink* const link : lane->getLinkCont()) {
428 if (&link->getLane()->getEdge() == nextEdge) {
429 return link;
430 }
431 }
432 }
433 }
434 }
435 return nullptr;
436}
437
438
439bool
440MESegment::isOpen(const MEVehicle* veh) const {
441#ifdef DEBUG_OPENED
442 if (DEBUG_COND || DEBUG_COND2(veh)) {
443 gDebugFlag1 = true;
444 std::cout << SIMTIME << " opened seg=" << getID() << " veh=" << Named::getIDSecure(veh)
445 << " tlsPenalty=" << myTLSPenalty;
446 const MSLink* link = getLink(veh);
447 if (link == 0) {
448 std::cout << " link=0";
449 } else {
450 std::cout << " prio=" << link->havePriority()
451 << " override=" << limitedControlOverride(link)
452 << " isOpen=" << link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
455 << " et=" << veh->getEventTime()
456 << " v=" << veh->getSpeed()
457 << " vLeave=" << veh->estimateLeaveSpeed(link)
458 << " impatience=" << veh->getImpatience()
459 << " tWait=" << veh->getWaitingTime();
460 }
461 std::cout << "\n";
462 gDebugFlag1 = false;
463 }
464#endif
465 if (myTLSPenalty) {
466 // XXX should limited control take precedence over tls penalty?
467 return true;
468 }
469 const MSLink* link = getLink(veh);
470 return (link == nullptr
471 || link->havePriority()
473 || link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
476}
477
478
479bool
481 assert(link != nullptr);
483 return false;
484 }
485 // if the target segment of this link is not saturated junction control is disabled
486 const MSEdge& targetEdge = link->getLane()->getEdge();
487 const MESegment* target = MSGlobals::gMesoNet->getSegmentForEdge(targetEdge);
488 return (target->getBruttoOccupancy() * 2 < target->myJamThreshold) && !targetEdge.isRoundabout();
489}
490
491
492void
493MESegment::send(MEVehicle* veh, MESegment* const next, const int nextQIdx, SUMOTime time, const MSMoveReminder::Notification reason) {
494 Queue& q = myQueues[veh->getQueIndex()];
495 assert(isInvalid(next) || time >= q.getBlockTime());
496 MSLink* const link = getLink(veh);
497 if (link != nullptr) {
498 link->removeApproaching(veh);
499 }
500 if (veh->isStopped()) {
501 veh->processStop();
502 }
503 MEVehicle* lc = removeCar(veh, time, reason); // new leaderCar
504 q.setBlockTime(time);
505 if (!isInvalid(next)) {
506 const bool nextFree = next->myQueues[nextQIdx].getOccupancy() <= next->myJamThreshold;
507 const SUMOTime tau = (q.getOccupancy() <= myJamThreshold
508 ? (nextFree ? myTau_ff : myTau_fj)
509 : (nextFree ? myTau_jf : getTauJJ((double)next->myQueues[nextQIdx].size(), next->myQueueCapacity, next->myJamThreshold)));
510 assert(tau >= 0);
512 if (myTLSPenalty) {
513 const MSLink* const tllink = getLink(veh, true);
514 if (tllink != nullptr && tllink->isTLSControlled()) {
515 assert(tllink->getGreenFraction() > 0);
516 myLastHeadway = (SUMOTime)((double)myLastHeadway / tllink->getGreenFraction());
517 }
518 }
520 }
521 if (lc != nullptr) {
524 }
525}
526
528MESegment::getTauJJ(double nextQueueSize, double nextQueueCapacity, double nextJamThreshold) const {
529 // compute coefficients for the jam-jam headway function
530 // this function models the effect that "empty space" needs to move
531 // backwards through the downstream segment before the upstream segment may
532 // send annother vehicle.
533 // this allows jams to clear and move upstream.
534 // the headway function f(x) depends on the number of vehicles in the
535 // downstream segment x
536 // f is a linear function that passes through the following fixed points:
537 // f(n_jam_threshold) = tau_jf_withLength (for continuity)
538 // f(headwayCapacity) = myTau_jj * headwayCapacity
539
540 const SUMOTime tau_jf_withLength = tauWithVehLength(myTau_jf, DEFAULT_VEH_LENGTH_WITH_GAP, 1.);
541 // number of vehicles that fit into the NEXT queue (could be larger than expected with DEFAULT_VEH_LENGTH_WITH_GAP!)
542 const double headwayCapacity = MAX2(nextQueueSize, nextQueueCapacity / DEFAULT_VEH_LENGTH_WITH_GAP);
543 // number of vehicles above which the NEXT queue is jammed
544 const double n_jam_threshold = headwayCapacity * nextJamThreshold / nextQueueCapacity;
545
546 // slope a and axis offset b for the jam-jam headway function
547 // solving f(x) = a * x + b
548 const double a = (STEPS2TIME(myTau_jj) * headwayCapacity - STEPS2TIME(tau_jf_withLength)) / (headwayCapacity - n_jam_threshold);
549 const double b = headwayCapacity * (STEPS2TIME(myTau_jj) - a);
550
551 // it is only well defined for nextQueueSize >= n_jam_threshold (which may not be the case for longer vehicles), so we take the MAX
552 return TIME2STEPS(a * MAX2(nextQueueSize, n_jam_threshold) + b);
553}
554
555
556bool
559}
560
561
562void
564 for (std::vector<MSMoveReminder*>::const_iterator i = myDetectorData.begin(); i != myDetectorData.end(); ++i) {
565 veh->addReminder(*i);
566 }
567}
568
569
570void
571MESegment::receive(MEVehicle* veh, const int qIdx, SUMOTime time, const bool isDepart, const bool isTeleport, const bool newEdge) {
572 const double speed = isDepart ? -1 : MAX2(veh->getSpeed(), MESO_MIN_SPEED); // on the previous segment
573 veh->setSegment(this); // for arrival checking
574 veh->setLastEntryTime(time);
576 if (!isDepart && (
577 // arrival on entering a new edge
578 (newEdge && veh->moveRoutePointer())
579 // arrival on entering a new segment
580 || veh->hasArrived())) {
581 // route has ended
582 veh->setEventTime(time + TIME2STEPS(myLength / speed)); // for correct arrival speed
583 addReminders(veh);
585 veh->updateDetectors(time, true,
588 return;
589 }
590 assert(veh->getEdge() == &getEdge());
591 // route continues
592 const double maxSpeedOnEdge = veh->getEdge()->getVehicleMaxSpeed(veh);
593 const double uspeed = MAX2(maxSpeedOnEdge, MESO_MIN_SPEED);
594 Queue& q = myQueues[qIdx];
595 std::vector<MEVehicle*>& cars = q.getModifiableVehicles();
596 MEVehicle* newLeader = nullptr; // first vehicle in the current queue
597 const SUMOTime stopTime = veh->checkStop(time);
598 SUMOTime tleave = MAX2(stopTime + TIME2STEPS(myLength / uspeed) + getLinkPenalty(veh), q.getBlockTime());
599 if (veh->isStopped()) {
600 myEdge.addWaiting(veh);
601 }
602 if (veh->isParking()) {
603 veh->setEventTime(stopTime);
604 veh->setSegment(this, PARKING_QUEUE);
605 myEdge.getLanes()[0]->addParking(veh); // TODO for GUI only
606 } else {
607 myEdge.lock();
608 if (cars.empty()) {
609 cars.push_back(veh);
610 newLeader = veh;
611 } else {
612 SUMOTime leaderOut = cars[0]->getEventTime();
613 if (!isDepart && leaderOut > tleave && overtake()) {
614 if (cars.size() == 1) {
616 newLeader = veh;
617 }
618 cars.insert(cars.begin() + 1, veh);
619 } else {
620 tleave = MAX2(leaderOut + tauWithVehLength(myTau_ff, cars[0]->getVehicleType().getLengthWithGap(), cars[0]->getVehicleType().getCarFollowModel().getHeadwayTime()), tleave);
621 cars.insert(cars.begin(), veh);
622 }
623 }
624 myEdge.unlock();
626 if (!isDepart && !isTeleport) {
627 // departs and teleports could take place anywhere on the edge so they should not block regular flow
628 // the -1 facilitates interleaving of multiple streams
630 }
632 veh->setEventTime(tleave);
633 veh->setSegment(this, qIdx);
634 }
635 addReminders(veh);
636 if (isDepart) {
637 veh->onDepart();
639 } else if (newEdge) {
641 } else {
643 }
644 if (veh->isParking()) {
645 MSGlobals::gMesoNet->addLeaderCar(veh, nullptr);
646 } else {
647 if (newLeader != nullptr) {
648 MSGlobals::gMesoNet->addLeaderCar(newLeader, getLink(newLeader));
649 }
650 }
651}
652
653
654bool
656 for (const Queue& q : myQueues) {
657 if (q.size() > 0) {
658 for (MEVehicle* const veh : q.getVehicles()) {
659 if (filter->vehicleApplies(*veh)) {
662 return true;
663 }
664 }
665 }
666 }
667 return false;
668}
669
670
671void
672MESegment::setSpeedForQueue(double newSpeed, SUMOTime currentTime, SUMOTime blockTime, const std::vector<MEVehicle*>& vehs) {
673 MEVehicle* v = vehs.back();
674 v->updateDetectors(currentTime, false);
675 SUMOTime newEvent = MAX2(newArrival(v, newSpeed, currentTime), blockTime);
676 if (v->getEventTime() != newEvent) {
678 v->setEventTime(newEvent);
680 }
681 for (std::vector<MEVehicle*>::const_reverse_iterator i = vehs.rbegin() + 1; i != vehs.rend(); ++i) {
682 (*i)->updateDetectors(currentTime, false);
683 newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + myTau_ff);
684 //newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + myTau_ff + (SUMOTime)((*(i - 1))->getVehicleType().getLength() / myTau_length));
685 (*i)->setEventTime(newEvent);
686 }
687}
688
689
691MESegment::newArrival(const MEVehicle* const v, double newSpeed, SUMOTime currentTime) {
692 // since speed is only an upper bound pos may be to optimistic
693 const double pos = MIN2(myLength, STEPS2TIME(currentTime - v->getLastEntryTime()) * v->getSpeed());
694 // traveltime may not be 0
695 return currentTime + MAX2(TIME2STEPS((myLength - pos) / newSpeed), SUMOTime(1));
696}
697
698
699void
700MESegment::setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh) {
701 recomputeJamThreshold(jamThresh);
702 //myTau_length = MAX2(MESO_MIN_SPEED, newSpeed) * myEdge.getLanes().size() / TIME2STEPS(1);
703 for (const Queue& q : myQueues) {
704 if (q.size() != 0) {
705 setSpeedForQueue(newSpeed, currentTime, q.getBlockTime(), q.getVehicles());
706 }
707 }
708}
709
710
713 SUMOTime result = SUMOTime_MAX;
714 for (const Queue& q : myQueues) {
715 if (q.size() != 0 && q.getVehicles().back()->getEventTime() < result) {
716 result = q.getVehicles().back()->getEventTime();
717 }
718 }
719 if (result < SUMOTime_MAX) {
720 return result;
721 }
722 return -1;
723}
724
725
726void
728 bool write = false;
729 for (const Queue& q : myQueues) {
730 if (q.getBlockTime() != -1 || !q.getVehicles().empty()) {
731 write = true;
732 break;
733 }
734 }
735 if (write) {
737 for (const Queue& q : myQueues) {
738 out.openTag(SUMO_TAG_VIEWSETTINGS_VEHICLES).writeAttr(SUMO_ATTR_TIME, toString<SUMOTime>(q.getBlockTime()));
739 out.writeAttr(SUMO_ATTR_VALUE, q.getVehicles());
740 out.closeTag();
741 }
742 out.closeTag();
743 }
744}
745
746
747void
749 for (Queue& q : myQueues) {
750 q.getModifiableVehicles().clear();
751 }
752}
753
754void
755MESegment::loadState(const std::vector<std::string>& vehIds, MSVehicleControl& vc, const SUMOTime block, const int queIdx) {
756 Queue& q = myQueues[queIdx];
757 for (const std::string& id : vehIds) {
758 MEVehicle* v = static_cast<MEVehicle*>(vc.getVehicle(id));
759 // vehicle could be removed due to options
760 if (v != nullptr) {
761 assert(v->getSegment() == this);
762 q.getModifiableVehicles().push_back(v);
765 }
766 }
767 if (q.size() != 0) {
768 // add the last vehicle of this queue
769 // !!! one question - what about the previously added vehicle? Is it stored twice?
770 MEVehicle* veh = q.getVehicles().back();
772 }
773 q.setBlockTime(block);
775}
776
777
778std::vector<const MEVehicle*>
780 std::vector<const MEVehicle*> result;
781 for (const Queue& q : myQueues) {
782 result.insert(result.end(), q.getVehicles().begin(), q.getVehicles().end());
783 }
784 return result;
785}
786
787
788bool
790 for (const Queue& q : myQueues) {
791 if (q.size() > 0 && q.getVehicles().back()->getWaitingTime() > 0) {
792 return true;
793 }
794 }
795 return false;
796}
797
798
799double
801 return 3600 * getCarNumber() * getMeanSpeed() / myLength;
802}
803
804
807 const MSLink* link = getLink(veh, myTLSPenalty || myCheckMinorPenalty);
808 if (link != nullptr) {
809 SUMOTime result = 0;
810 if (link->isTLSControlled()) {
811 result += link->getMesoTLSPenalty();
812 }
813 // minor tls links may get an additional penalty
814 if (!link->havePriority() &&
815 // do not apply penalty on top of tLSPenalty
816 !myTLSPenalty &&
817 // do not apply penalty if limited control is active
819 result += myMinorPenalty;
820 }
821 return result;
822 } else {
823 return 0;
824 }
825}
826
827
828double
830 double result = 0;
831 for (const Queue& q : myQueues) {
832 // @note: only the leader currently accumulates waitingTime but this might change in the future
833 for (const MEVehicle* veh : q.getVehicles()) {
834 result += veh->getWaitingSeconds();
835 }
836 }
837 return result;
838}
839
840
841/****************************************************************************/
long long int SUMOTime
Definition: GUI.h:36
#define MESO_MIN_SPEED
Definition: MESegment.cpp:45
#define DEFAULT_VEH_LENGTH_WITH_GAP
Definition: MESegment.cpp:43
#define DEBUG_COND
Definition: MESegment.cpp:51
#define DEBUG_COND2(obj)
Definition: MESegment.cpp:52
#define STEPS2TIME(x)
Definition: SUMOTime.h:54
#define SUMOTime_MAX
Definition: SUMOTime.h:33
#define SUMOTime_MIN
Definition: SUMOTime.h:34
#define SIMTIME
Definition: SUMOTime.h:61
#define TIME2STEPS(x)
Definition: SUMOTime.h:56
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
@ SUMO_TAG_VIEWSETTINGS_VEHICLES
@ SUMO_TAG_SEGMENT
segment of a lane
@ SUMO_ATTR_VALUE
@ SUMO_ATTR_ID
@ SUMO_ATTR_TIME
trigger: the time of the step
bool gDebugFlag1
global utility flags for debugging
Definition: StdDefs.cpp:33
T MIN2(T a, T b)
Definition: StdDefs.h:71
T MAX2(T a, T b)
Definition: StdDefs.h:77
T MAX3(T a, T b, T c)
Definition: StdDefs.h:91
static bool isEnteringRoundabout(const MSEdge &e)
whether the given edge is entering a roundabout
Definition: MELoop.cpp:331
SUMOTime changeSegment(MEVehicle *veh, SUMOTime leaveTime, MESegment *const toSegment, MSMoveReminder::Notification reason, const bool ignoreLink=false) const
change to the next segment this handles combinations of the following cases: (ending / continuing rou...
Definition: MELoop.cpp:79
MESegment * getSegmentForEdge(const MSEdge &e, double pos=0)
Get the segment for a given edge at a given position.
Definition: MELoop.cpp:314
bool removeLeaderCar(MEVehicle *v)
Removes the given car from the leading vehicles.
Definition: MELoop.cpp:225
void addLeaderCar(MEVehicle *veh, MSLink *link)
Adds the given car to the leading vehicles.
Definition: MELoop.cpp:212
int size() const
Definition: MESegment.h:73
void setOccupancy(const double occ)
Definition: MESegment.h:86
MEVehicle * remove(MEVehicle *v)
Definition: MESegment.cpp:67
void setBlockTime(SUMOTime t)
Definition: MESegment.h:106
SUMOTime getBlockTime() const
Definition: MESegment.h:103
double myOccupancy
The occupied space (in m) in the queue.
Definition: MESegment.h:121
bool allows(SUMOVehicleClass vclass) const
Definition: MESegment.h:89
std::vector< MEVehicle * > & getModifiableVehicles()
Definition: MESegment.h:80
void setEntryBlockTime(SUMOTime entryBlockTime)
set the next time at which a vehicle may enter this queue
Definition: MESegment.h:99
double getOccupancy() const
Definition: MESegment.h:83
std::vector< MEVehicle * > myVehicles
Definition: MESegment.h:118
const std::vector< MEVehicle * > & getVehicles() const
Definition: MESegment.h:76
SUMOTime getEntryBlockTime() const
return the next time at which a vehicle may enter this queue
Definition: MESegment.h:94
A single mesoscopic segment (cell)
Definition: MESegment.h:49
void addReminders(MEVehicle *veh) const
add this lanes MoveReminders to the given vehicle
Definition: MESegment.cpp:563
double myQueueCapacity
The number of lanes represented by the queue * the length of the lane.
Definition: MESegment.h:542
bool overtake()
Definition: MESegment.cpp:557
SUMOTime tauWithVehLength(SUMOTime tau, double lengthWithGap, double vehicleTau) const
convert net time gap (leader back to follower front) to gross time gap (leader front to follower fron...
Definition: MESegment.h:496
SUMOTime myTau_ff
The time headway parameters, see the Eissfeldt thesis.
Definition: MESegment.h:519
bool initialise(MEVehicle *veh, SUMOTime time)
Inserts (emits) vehicle into the segment.
Definition: MESegment.cpp:329
std::vector< Queue > myQueues
The car queues. Vehicles are inserted in the front and removed in the back.
Definition: MESegment.h:551
double getBruttoOccupancy() const
Returns the occupany of the segment (the sum of the vehicle lengths + minGaps)
Definition: MESegment.h:247
SUMOTime myLastHeadway
the last headway
Definition: MESegment.h:560
static const int PARKING_QUEUE
Definition: MESegment.h:52
bool limitedControlOverride(const MSLink *link) const
whether the given link may be passed because the option meso-junction-control.limited is set
Definition: MESegment.cpp:480
bool isOpen(const MEVehicle *veh) const
Returns whether the vehicle may use the next link.
Definition: MESegment.cpp:440
void clearState()
Remove all vehicles before quick-loading state.
Definition: MESegment.cpp:748
void receive(MEVehicle *veh, const int qIdx, SUMOTime time, const bool isDepart=false, const bool isTeleport=false, const bool newEdge=false)
Adds the vehicle to the segment, adapting its parameters.
Definition: MESegment.cpp:571
SUMOTime getLinkPenalty(const MEVehicle *veh) const
Returns the penalty time for passing a link (if using gMesoTLSPenalty > 0 or gMesoMinorPenalty > 0)
Definition: MESegment.cpp:806
void writeVehicles(OutputDevice &of) const
Definition: MESegment.cpp:371
std::map< const MSEdge *, int > myFollowerMap
The follower edge to allowed que index mapping for multi queue segments.
Definition: MESegment.h:557
MSLink * getLink(const MEVehicle *veh, bool tlsPenalty=false) const
Returns the link the given car will use when passing the next junction.
Definition: MESegment.cpp:411
int myNumVehicles
The cached value for the number of vehicles.
Definition: MESegment.h:554
void setSpeedForQueue(double newSpeed, SUMOTime currentTime, SUMOTime blockTime, const std::vector< MEVehicle * > &vehs)
Definition: MESegment.cpp:672
SUMOTime hasSpaceFor(const MEVehicle *const veh, const SUMOTime entryTime, int &qIdx, const bool init=false) const
Returns whether the given vehicle would still fit into the segment.
Definition: MESegment.cpp:275
void updatePermissions()
called when permissions change due to Rerouter or TraCI
Definition: MESegment.cpp:190
void removeDetector(MSMoveReminder *data)
Removes a data collector for a detector from this segment.
Definition: MESegment.cpp:247
void saveState(OutputDevice &out) const
Saves the state of this segment into the given stream.
Definition: MESegment.cpp:727
void initSegment(const MesoEdgeType &edgeType, const MSEdge &parent, const double capacity)
set model parameters (may be updated from additional file after network loading is complete)
Definition: MESegment.cpp:133
void prepareDetectorForWriting(MSMoveReminder &data)
Updates data of a detector for all vehicle queues.
Definition: MESegment.cpp:261
const MSEdge & getEdge() const
Returns the edge this segment belongs to.
Definition: MESegment.h:348
static MESegment myVaporizationTarget
Definition: MESegment.h:565
double myJamThreshold
The space (in m) which needs to be occupied before the segment is considered jammed.
Definition: MESegment.h:545
const int myIndex
Running number of the segment in the edge.
Definition: MESegment.h:513
void send(MEVehicle *veh, MESegment *const next, const int nextQIdx, SUMOTime time, const MSMoveReminder::Notification reason)
Removes the vehicle from the segment, adapting its parameters.
Definition: MESegment.cpp:493
SUMOTime myMinorPenalty
Definition: MESegment.h:526
double myMeanSpeed
the mean speed on this segment. Updated at event time or on demand
Definition: MESegment.h:568
bool myCheckMinorPenalty
penalty for minor links
Definition: MESegment.h:525
std::vector< MSMoveReminder * > myDetectorData
The data collection for all kinds of detectors.
Definition: MESegment.h:548
double jamThresholdForSpeed(double speed, double jamThresh) const
compute jam threshold for the given speed and jam-threshold option
Definition: MESegment.cpp:217
SUMOTime myLastMeanSpeedUpdate
the time at which myMeanSpeed was last updated
Definition: MESegment.h:571
SUMOTime myTau_jf
Definition: MESegment.h:519
MESegment * myNextSegment
The next segment of this edge, 0 if this is the last segment of this edge.
Definition: MESegment.h:507
bool hasBlockedLeader() const
whether a leader in any queue is blocked
Definition: MESegment.cpp:789
double getWaitingSeconds() const
Get the waiting time for vehicles in all queues.
Definition: MESegment.cpp:829
const double myLength
The segment's length.
Definition: MESegment.h:510
SUMOTime getEventTime() const
Returns the (planned) time at which the next vehicle leaves this segment.
Definition: MESegment.cpp:712
const MSEdge & myEdge
The microsim edge this segment belongs to.
Definition: MESegment.h:504
MESegment(const std::string &id, const MSEdge &parent, MESegment *next, const double length, const double speed, const int idx, const bool multiQueue, const MesoEdgeType &edgeType)
constructor
Definition: MESegment.cpp:87
MEVehicle * removeCar(MEVehicle *v, SUMOTime leaveTime, const MSMoveReminder::Notification reason)
Removes the given car from the edge's que.
Definition: MESegment.cpp:381
std::vector< const MEVehicle * > getVehicles() const
returns all vehicles (for debugging)
Definition: MESegment.cpp:779
void addDetector(MSMoveReminder *data)
Adds a data collector for a detector to this segment.
Definition: MESegment.cpp:236
static MSEdge myDummyParent
Definition: MESegment.h:564
void recomputeJamThreshold(double jamThresh)
compute a value for myJamThreshold if jamThresh is negative, compute a value which allows free flow a...
Definition: MESegment.cpp:202
double getMeanSpeed() const
wrapper to satisfy the FunctionBinding signature
Definition: MESegment.h:283
int getCarNumber() const
Returns the total number of cars on the segment.
Definition: MESegment.h:195
void setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh=DO_NOT_PATCH_JAM_THRESHOLD)
reset mySpeed and patch the speed of all vehicles in it. Also set/recompute myJamThreshold
Definition: MESegment.cpp:700
void loadState(const std::vector< std::string > &vehIDs, MSVehicleControl &vc, const SUMOTime blockTime, const int queIdx)
Loads the state of this segment with the given parameters.
Definition: MESegment.cpp:755
double myTau_length
Headway parameter for computing gross time headyway from net time headway, length and edge speed.
Definition: MESegment.h:536
SUMOTime myTau_jj
Definition: MESegment.h:519
SUMOTime newArrival(const MEVehicle *const v, double newSpeed, SUMOTime currentTime)
compute the new arrival time when switching speed
Definition: MESegment.cpp:691
bool myJunctionControl
Whether junction control is enabled.
Definition: MESegment.h:529
bool myTLSPenalty
Whether tls penalty is enabled.
Definition: MESegment.h:522
static const double DO_NOT_PATCH_JAM_THRESHOLD
Definition: MESegment.h:51
double getFlow() const
returns flow based on headway
Definition: MESegment.cpp:800
static bool isInvalid(const MESegment *segment)
whether the given segment is 0 or encodes vaporization
Definition: MESegment.h:432
SUMOTime getNextInsertionTime(SUMOTime earliestEntry) const
return a time after earliestEntry at which a vehicle may be inserted at full speed
Definition: MESegment.cpp:394
double myCapacity
The number of lanes represented by the queue * the length of the lane.
Definition: MESegment.h:539
bool myOvertaking
Whether overtaking is permitted on this segment.
Definition: MESegment.h:532
bool vaporizeAnyCar(SUMOTime currentTime, const MSDetectorFileOutput *filter)
tries to remove any car from this segment
Definition: MESegment.cpp:655
SUMOTime myTau_fj
Definition: MESegment.h:519
SUMOTime getTauJJ(double nextQueueSize, double nextQueueCapacity, double nextJamThreshold) const
Definition: MESegment.cpp:528
A vehicle from the mesoscopic point of view.
Definition: MEVehicle.h:42
double estimateLeaveSpeed(const MSLink *link) const
Returns the vehicle's estimated speed after driving accross the link.
Definition: MEVehicle.cpp:124
void processStop()
ends the current stop and performs loading/unloading
Definition: MEVehicle.cpp:315
bool hasArrived() const
Returns whether this vehicle has already arived (reached the arrivalPosition on its final edge)
Definition: MEVehicle.cpp:158
bool moveRoutePointer()
Update when the vehicle enters a new edge in the move step.
Definition: MEVehicle.cpp:140
SUMOTime checkStop(SUMOTime time)
Returns until when to stop at the current segment and sets the information that the stop has been rea...
Definition: MEVehicle.cpp:214
void updateDetectors(SUMOTime currentTime, const bool isLeave, const MSMoveReminder::Notification reason=MSMoveReminder::NOTIFICATION_JUNCTION)
Updates all vehicle detectors.
Definition: MEVehicle.cpp:434
SUMOTime getLastEntryTime() const
Returns the time the vehicle entered the current segment.
Definition: MEVehicle.h:269
void setEventTime(SUMOTime t, bool hasDelay=true)
Sets the (planned) time at which the vehicle leaves his current cell.
Definition: MEVehicle.h:209
MESegment * getSegment() const
Returns the current segment the vehicle is on.
Definition: MEVehicle.h:239
void setLastEntryTime(SUMOTime t)
Sets the entry time for the current segment.
Definition: MEVehicle.h:261
int getQueIndex() const
Returns the index of the que the vehicle is in.
Definition: MEVehicle.h:247
SUMOTime getWaitingTime() const
Returns the duration for which the vehicle was blocked.
Definition: MEVehicle.h:292
virtual void setSegment(MESegment *s, int idx=0)
Sets the current segment the vehicle is at together with its que.
Definition: MEVehicle.h:230
SUMOTime getEventTime() const
Returns the (planned) time at which the vehicle leaves his current cell.
Definition: MEVehicle.h:221
void setBlockTime(const SUMOTime t)
Sets the time at which the vehicle was blocked.
Definition: MEVehicle.h:277
double getSpeed() const
Returns the vehicle's estimated speed assuming no delays.
Definition: MEVehicle.cpp:108
double getImpatience() const
Returns this vehicles impatience.
const MSEdge * succEdge(int nSuccs) const
Returns the nSuccs'th successor of edge the vehicle is currently at.
void addReminder(MSMoveReminder *rem)
Adds a MoveReminder dynamically.
bool isParking() const
Returns whether the vehicle is parking.
const MSEdge * getEdge() const
Returns the edge the vehicle is currently at.
bool hasValidRoute(std::string &msg, const MSRoute *route=0) const
Validates the current or given route.
virtual void activateReminders(const MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
"Activates" all current move reminder
SUMOVehicleClass getVClass() const
Returns the vehicle's access class.
void onDepart()
Called when the vehicle is inserted into the network.
const MSVehicleType & getVehicleType() const
Returns the vehicle's type definition.
bool isStopped() const
Returns whether the vehicle is at a stop.
double getMaxDecel() const
Get the vehicle type's maximal comfortable deceleration [m/s^2].
Definition: MSCFModel.h:262
virtual double getHeadwayTime() const
Get the driver's desired headway [s].
Definition: MSCFModel.h:309
Base of value-generating classes (detectors)
bool vehicleApplies(const SUMOTrafficObject &veh) const
Checks whether the detector measures vehicles of the given type.
A road/street connecting two junctions.
Definition: MSEdge.h:77
virtual void unlock() const
release exclusive access to the mesoscopic state
Definition: MSEdge.h:747
SVCPermissions getPermissions() const
Returns the combined permissions of all lanes of this edge.
Definition: MSEdge.h:622
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:168
const std::vector< MSLane * > * allowedLanes(const MSEdge &destination, SUMOVehicleClass vclass=SVC_IGNORING) const
Get the allowed lanes to reach the destination-edge.
Definition: MSEdge.cpp:439
double getSpeedLimit() const
Returns the speed limit of the edge @caution The speed limit of the first lane is retured; should pro...
Definition: MSEdge.cpp:1056
const MSJunction * getToJunction() const
Definition: MSEdge.h:415
static SVCPermissions getMesoPermissions(SVCPermissions p, SVCPermissions ignoreIgnored=0)
Definition: MSEdge.cpp:293
bool isRoundabout() const
Definition: MSEdge.h:694
bool isVaporizing() const
Returns whether vehicles on this edge shall be vaporized.
Definition: MSEdge.h:431
void addWaiting(SUMOVehicle *vehicle) const
Adds a vehicle to the list of waiting vehicles.
Definition: MSEdge.cpp:1303
double getVehicleMaxSpeed(const SUMOTrafficObject *const veh) const
Returns the maximum speed the vehicle may use on this edge.
Definition: MSEdge.cpp:1068
bool hasMinorLink() const
whether any lane has a minor link
Definition: MSEdge.cpp:1246
virtual void lock() const
grant exclusive access to the mesoscopic state
Definition: MSEdge.h:744
const MSEdgeVector & getSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges, restricted by vClass.
Definition: MSEdge.cpp:1155
static bool gCheckRoutes
Definition: MSGlobals.h:88
static MELoop * gMesoNet
mesoscopic simulation infrastructure
Definition: MSGlobals.h:109
static bool gMesoLimitedJunctionControl
Definition: MSGlobals.h:106
SumoXMLNodeType getType() const
return the type of this Junction
Definition: MSJunction.h:130
Representation of a lane in the micro simulation.
Definition: MSLane.h:84
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:713
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.h:675
Something on a lane to be noticed about vehicle movement.
Notification
Definition of a vehicle state.
@ NOTIFICATION_ARRIVED
The vehicle arrived at its destination (is deleted)
@ NOTIFICATION_VAPORIZED_CALIBRATOR
The vehicle got removed by a calibrator.
@ NOTIFICATION_DEPARTED
The vehicle has departed (was inserted into the network)
@ NOTIFICATION_SEGMENT
The vehicle changes the segment (meso only)
@ NOTIFICATION_VAPORIZED_VAPORIZER
The vehicle got vaporized with a vaporizer.
@ NOTIFICATION_JUNCTION
The vehicle arrived at a junction.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:183
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:321
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:379
The class responsible for building and deletion of vehicles.
SUMOVehicle * getVehicle(const std::string &id) const
Returns the vehicle with the given id.
void scheduleVehicleRemoval(SUMOVehicle *veh, bool checkDuplicate=false)
Removes a vehicle after it has ended.
double getLengthWithGap() const
Get vehicle's length including the minimum gap [m].
const MSCFModel & getCarFollowModel() const
Returns the vehicle type's car following model definition (const version)
static void writeVehicle(OutputDevice &of, const MSBaseVehicle &veh)
Writes the dump of the given vehicle into the given device.
Base class for objects which have an id.
Definition: Named.h:54
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition: Named.h:67
const std::string & getID() const
Returns the id.
Definition: Named.h:74
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:61
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:251
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
Definition: RandHelper.cpp:94
edge type specific meso parameters
Definition: MESegment.h:55