Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MESegment.cpp
Go to the documentation of this file.
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/****************************************************************************/
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 definition
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
83void
85 myDetectorData.push_back(data);
86 for (MEVehicle* const v : myVehicles) {
87 v->addReminder(data);
88 }
89}
90
91void
93 for (MSMoveReminder* rem : myDetectorData) {
94 veh->addReminder(rem);
95 }
96}
97
98// ===========================================================================
99// MESegment method definitions
100// ===========================================================================
101MESegment::MESegment(const std::string& id,
102 const MSEdge& parent, MESegment* next,
103 const double length, const double speed,
104 const int idx,
105 const bool multiQueue,
106 const MesoEdgeType& edgeType):
107 Named(id), myEdge(parent), myNextSegment(next),
108 myLength(length), myIndex(idx),
110 myNumVehicles(0),
112 myMeanSpeed(speed),
114
115 const std::vector<MSLane*>& lanes = parent.getLanes();
116 int usableLanes = 0;
117 for (MSLane* const l : lanes) {
118 const SVCPermissions allow = MSEdge::getMesoPermissions(l->getPermissions());
119 if (multiQueue) {
120 myQueues.push_back(Queue(allow));
121 }
122 if (allow != 0) {
123 usableLanes++;
124 }
125 }
126 if (usableLanes == 0) {
127 // cars won't drive here. Give sensible tau values capacity for the ignored classes
128 usableLanes = 1;
129 }
130 if (multiQueue) {
131 if (next == nullptr) {
132 for (const MSEdge* const edge : parent.getSuccessors()) {
133 const std::vector<MSLane*>* const allowed = parent.allowedLanes(*edge);
134 assert(allowed != nullptr);
135 assert(allowed->size() > 0);
136 for (MSLane* const l : *allowed) {
137 std::vector<MSLane*>::const_iterator it = std::find(lanes.begin(), lanes.end(), l);
138 myFollowerMap[edge] |= (1 << distance(lanes.begin(), it));
139 }
140 }
141 }
142 myQueueCapacity = length;
143 } else {
144 myQueues.push_back(Queue(parent.getPermissions()));
145 }
146
147 initSegment(edgeType, parent, length * usableLanes);
148}
149
150void
151MESegment::initSegment(const MesoEdgeType& edgeType, const MSEdge& parent, const double capacity) {
152
153 myCapacity = capacity;
154 if (myQueues.size() == 1) {
155 const double laneScale = capacity / myLength;
156 myQueueCapacity = capacity;
158 // Eissfeldt p. 90 and 151 ff.
159 myTau_ff = (SUMOTime)((double)edgeType.tauff / laneScale);
160 myTau_fj = (SUMOTime)((double)edgeType.taufj / laneScale);
161 myTau_jf = (SUMOTime)((double)edgeType.taujf / laneScale);
162 myTau_jj = (SUMOTime)((double)edgeType.taujj / laneScale);
163 } else {
164 myTau_ff = edgeType.tauff;
165 myTau_fj = edgeType.taufj;
166 myTau_jf = edgeType.taujf;
167 myTau_jj = edgeType.taujj;
168 }
169
171 myTLSPenalty = ((edgeType.tlsPenalty > 0 || edgeType.tlsFlowPenalty > 0) &&
172 // only apply to the last segment of a tls-controlled edge
173 myNextSegment == nullptr && (
177
178 // only apply to the last segment of an uncontrolled edge that has at least 1 minor link
179 myCheckMinorPenalty = (edgeType.minorPenalty > 0 &&
180 myNextSegment == nullptr &&
184 parent.hasMinorLink());
185 myMinorPenalty = edgeType.minorPenalty;
187
188 //std::cout << getID() << " myMinorPenalty=" << myMinorPenalty << " myTLSPenalty=" << myTLSPenalty << " myJunctionControl=" << myJunctionControl << " myOvertaking=" << myOvertaking << "\n";
189
191}
192
193MESegment::MESegment(const std::string& id):
194 Named(id),
195 myEdge(myDummyParent), // arbitrary edge needed to supply the needed reference
196 myNextSegment(nullptr), myLength(0), myIndex(0),
197 myTau_ff(0), myTau_fj(0), myTau_jf(0), myTau_jj(0),
198 myTLSPenalty(false),
199 myCheckMinorPenalty(false),
200 myMinorPenalty(0),
201 myJunctionControl(false),
202 myOvertaking(false),
203 myTau_length(1) {
204}
205
206
207void
209 if (myQueues.size() > 1) {
210 for (MSLane* lane : myEdge.getLanes()) {
211 myQueues[lane->getIndex()].setPermissions(lane->getPermissions());
212 }
213 } else {
214 myQueues.back().setPermissions(myEdge.getPermissions());
215 }
216}
217
218
219void
221 if (jamThresh == DO_NOT_PATCH_JAM_THRESHOLD) {
222 return;
223 }
224 if (jamThresh < 0) {
225 // compute based on speed
227 } else {
228 // compute based on specified percentage
229 myJamThreshold = jamThresh * myCapacity;
230 }
231}
232
233
234double
235MESegment::jamThresholdForSpeed(double speed, double jamThresh) const {
236 // vehicles driving freely at maximum speed should not jam
237 // we compute how many vehicles could possible enter the segment until the first vehicle leaves
238 // and multiply by the space these vehicles would occupy
239 // the jamThresh parameter is scale the resulting value
240 if (speed == 0) {
241 return std::numeric_limits<double>::max(); // never jam. Irrelevant at speed 0 anyway
242 }
243#ifdef DEBUG_JAMTHRESHOLD
244 if (true || DEBUG_COND) {
245 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
246 << "\n";
247 }
248#endif
250}
251
252
253void
255 if (queueIndex == -1) {
256 for (Queue& q : myQueues) {
257 q.addDetector(data);
258 }
259 } else {
260 assert(queueIndex < (int)myQueues.size());
261 myQueues[queueIndex].addDetector(data);
262 }
263}
264
265
266/*
267void
268MESegment::removeDetector(MSMoveReminder* data) {
269 std::vector<MSMoveReminder*>::iterator it = std::find(myDetectorData.begin(), myDetectorData.end(), data);
270 if (it != myDetectorData.end()) {
271 myDetectorData.erase(it);
272 }
273 for (const Queue& q : myQueues) {
274 for (MEVehicle* const v : q.getVehicles()) {
275 v->removeReminder(data);
276 }
277 }
278}
279*/
280
281
282void
284 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
285 if (queueIndex == -1) {
286 for (const Queue& q : myQueues) {
287 SUMOTime earliestExitTime = currentTime;
288 for (std::vector<MEVehicle*>::const_reverse_iterator i = q.getVehicles().rbegin(); i != q.getVehicles().rend(); ++i) {
289 const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
290 (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
291 earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
292 }
293 }
294 } else {
295 SUMOTime earliestExitTime = currentTime;
296 for (std::vector<MEVehicle*>::const_reverse_iterator i = myQueues[queueIndex].getVehicles().rbegin(); i != myQueues[queueIndex].getVehicles().rend(); ++i) {
297 const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
298 (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
299 earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
300 }
301 }
302}
303
304
306MESegment::hasSpaceFor(const MEVehicle* const veh, const SUMOTime entryTime, int& qIdx, const bool init) const {
307 SUMOTime earliestEntry = SUMOTime_MAX;
308 qIdx = 0;
309 if (myNumVehicles == 0 && myQueues.size() == 1) {
310 // we have always space for at least one vehicle
311 if (myQueues.front().allows(veh->getVClass())) {
312 return entryTime;
313 } else {
314 return earliestEntry;
315 }
316 }
317 const SUMOVehicleClass svc = veh->getVClass();
318 int minSize = std::numeric_limits<int>::max();
319 const MSEdge* const succ = myNextSegment == nullptr ? veh->succEdge(1) : nullptr;
320 for (int i = 0; i < (int)myQueues.size(); i++) {
321 const Queue& q = myQueues[i];
322 const double newOccupancy = q.size() == 0 ? 0. : q.getOccupancy() + veh->getVehicleType().getLengthWithGap();
323 if (newOccupancy <= myQueueCapacity) { // we must ensure that occupancy remains below capacity
324 if (succ == nullptr || myFollowerMap.count(succ) == 0 || ((myFollowerMap.find(succ)->second & (1 << i)) != 0)) {
325 if (q.allows(svc) && q.size() < minSize) {
326 if (init) {
327 // regular insertions and initial insertions must respect different constraints:
328 // - regular insertions must respect entryBlockTime
329 // - initial insertions should not cause additional jamming
330 // - inserted vehicle should be able to continue at the current speed
332 if (newOccupancy <= myJamThreshold) {
333 qIdx = i;
334 minSize = q.size();
335 }
336 } else {
337 if (newOccupancy <= jamThresholdForSpeed(getMeanSpeed(false), -1)) {
338 qIdx = i;
339 minSize = q.size();
340 }
341 }
342 } else if (entryTime >= q.getEntryBlockTime()) {
343 qIdx = i;
344 minSize = q.size();
345 } else {
346 earliestEntry = MIN2(earliestEntry, q.getEntryBlockTime());
347 }
348 }
349 }
350 }
351 }
352 if (minSize == std::numeric_limits<int>::max()) {
353 return earliestEntry;
354 }
355 return entryTime;
356}
357
358
359bool
361 int qIdx = 0;
362 if (hasSpaceFor(veh, time, qIdx, true) == time) {
363 receive(veh, qIdx, time, true);
364 // we can check only after insertion because insertion may change the route via devices
365 std::string msg;
366 if (MSGlobals::gCheckRoutes && !veh->hasValidRoute(msg)) {
367 throw ProcessError("Vehicle '" + veh->getID() + "' has no valid route. " + msg);
368 }
369 return true;
370 }
371 return false;
372}
373
374
375double
376MESegment::getMeanSpeed(bool useCached) const {
377 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
378 if (currentTime != myLastMeanSpeedUpdate || !useCached) {
379 myLastMeanSpeedUpdate = currentTime;
380 double v = 0;
381 int count = 0;
382 for (const Queue& q : myQueues) {
383 const SUMOTime tau = q.getOccupancy() < myJamThreshold ? myTau_ff : myTau_jf;
384 SUMOTime earliestExitTime = currentTime;
385 count += q.size();
386 for (std::vector<MEVehicle*>::const_reverse_iterator veh = q.getVehicles().rbegin(); veh != q.getVehicles().rend(); ++veh) {
387 v += (*veh)->getConservativeSpeed(earliestExitTime); // earliestExitTime is updated!
388 earliestExitTime += tauWithVehLength(tau, (*veh)->getVehicleType().getLengthWithGap(), (*veh)->getVehicleType().getCarFollowModel().getHeadwayTime());
389 }
390 }
391 if (count == 0) {
393 } else {
394 myMeanSpeed = v / (double) count;
395 }
396 }
397 return myMeanSpeed;
398}
399
400
401void
403 for (const Queue& q : myQueues) {
404 for (const MEVehicle* const veh : q.getVehicles()) {
406 }
407 }
408}
409
410
413 Queue& q = myQueues[v->getQueIndex()];
414 // One could be tempted to do v->setSegment(next); here but position on lane will be invalid if next == 0
415 v->updateDetectors(leaveTime, true, reason);
417 myEdge.lock();
418 MEVehicle* nextLeader = q.remove(v);
419 myEdge.unlock();
420 return nextLeader;
421}
422
423
426 // since we do not know which queue will be used we give a conservative estimate
427 SUMOTime earliestLeave = earliestEntry;
428 SUMOTime latestEntry = -1;
429 for (const Queue& q : myQueues) {
430 earliestLeave = MAX2(earliestLeave, q.getBlockTime());
431 latestEntry = MAX2(latestEntry, q.getEntryBlockTime());
432 }
433 if (myEdge.getSpeedLimit() == 0) {
434 return MAX2(earliestEntry, latestEntry); // FIXME: This line is just an adhoc-fix to avoid division by zero (Leo)
435 } else {
436 return MAX3(earliestEntry, earliestLeave - TIME2STEPS(myLength / myEdge.getSpeedLimit()), latestEntry);
437 }
438}
439
440
441MSLink*
442MESegment::getLink(const MEVehicle* veh, bool penalty) const {
443 if (myJunctionControl || penalty) {
444 const MSEdge* const nextEdge = veh->succEdge(1);
445 if (nextEdge == nullptr || veh->getQueIndex() == PARKING_QUEUE) {
446 return nullptr;
447 }
448 // try to find any link leading to our next edge, start with the lane pointed to by the que index
449 const MSLane* const bestLane = myEdge.getLanes()[veh->getQueIndex()];
450 for (MSLink* const link : bestLane->getLinkCont()) {
451 if (&link->getLane()->getEdge() == nextEdge) {
452 return link;
453 }
454 }
455 // this is for the non-multique case, maybe we should use caching here !!!
456 for (const MSLane* const lane : myEdge.getLanes()) {
457 if (lane != bestLane) {
458 for (MSLink* const link : lane->getLinkCont()) {
459 if (&link->getLane()->getEdge() == nextEdge) {
460 return link;
461 }
462 }
463 }
464 }
465 }
466 return nullptr;
467}
468
469
470bool
471MESegment::isOpen(const MEVehicle* veh) const {
472#ifdef DEBUG_OPENED
473 if (DEBUG_COND || DEBUG_COND2(veh)) {
474 gDebugFlag1 = true;
475 std::cout << SIMTIME << " opened seg=" << getID() << " veh=" << Named::getIDSecure(veh)
476 << " tlsPenalty=" << myTLSPenalty;
477 const MSLink* link = getLink(veh);
478 if (link == 0) {
479 std::cout << " link=0";
480 } else {
481 std::cout << " prio=" << link->havePriority()
482 << " override=" << limitedControlOverride(link)
483 << " isOpen=" << link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
486 0, nullptr, false, veh)
487 << " et=" << veh->getEventTime()
488 << " v=" << veh->getSpeed()
489 << " vLeave=" << veh->estimateLeaveSpeed(link)
490 << " impatience=" << veh->getImpatience()
491 << " tWait=" << veh->getWaitingTime();
492 }
493 std::cout << "\n";
494 gDebugFlag1 = false;
495 }
496#endif
497 if (myTLSPenalty) {
498 // XXX should limited control take precedence over tls penalty?
499 return true;
500 }
501 const MSLink* link = getLink(veh);
502 return (link == nullptr
503 || link->havePriority()
505 || link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
508 0, nullptr, false, veh));
509}
510
511
512bool
514 assert(link != nullptr);
516 return false;
517 }
518 // if the target segment of this link is not saturated junction control is disabled
519 const MSEdge& targetEdge = link->getLane()->getEdge();
520 const MESegment* target = MSGlobals::gMesoNet->getSegmentForEdge(targetEdge);
521 return (target->getBruttoOccupancy() * 2 < target->myJamThreshold) && !targetEdge.isRoundabout();
522}
523
524
525void
526MESegment::send(MEVehicle* veh, MESegment* const next, const int nextQIdx, SUMOTime time, const MSMoveReminder::Notification reason) {
527 Queue& q = myQueues[veh->getQueIndex()];
528 assert(isInvalid(next) || time >= q.getBlockTime());
529 MSLink* const link = getLink(veh);
530 if (link != nullptr) {
531 link->removeApproaching(veh);
532 }
533 if (veh->isStopped()) {
534 veh->processStop();
535 }
536 MEVehicle* lc = removeCar(veh, time, reason); // new leaderCar
537 q.setBlockTime(time);
538 if (!isInvalid(next)) {
539 const bool nextFree = next->myQueues[nextQIdx].getOccupancy() <= next->myJamThreshold;
540 const SUMOTime tau = (q.getOccupancy() <= myJamThreshold
541 ? (nextFree ? myTau_ff : myTau_fj)
542 : (nextFree ? myTau_jf : getTauJJ((double)next->myQueues[nextQIdx].size(), next->myQueueCapacity, next->myJamThreshold)));
543 assert(tau >= 0);
545 if (myTLSPenalty) {
546 const MSLink* const tllink = getLink(veh, true);
547 if (tllink != nullptr && tllink->isTLSControlled()) {
548 assert(tllink->getGreenFraction() > 0);
549 myLastHeadway = (SUMOTime)((double)myLastHeadway / tllink->getGreenFraction());
550 }
551 }
553 }
554 if (lc != nullptr) {
557 }
558}
559
561MESegment::getTauJJ(double nextQueueSize, double nextQueueCapacity, double nextJamThreshold) const {
562 // compute coefficients for the jam-jam headway function
563 // this function models the effect that "empty space" needs to move
564 // backwards through the downstream segment before the upstream segment may
565 // send annother vehicle.
566 // this allows jams to clear and move upstream.
567 // the headway function f(x) depends on the number of vehicles in the
568 // downstream segment x
569 // f is a linear function that passes through the following fixed points:
570 // f(n_jam_threshold) = tau_jf_withLength (for continuity)
571 // f(headwayCapacity) = myTau_jj * headwayCapacity
572
573 const SUMOTime tau_jf_withLength = tauWithVehLength(myTau_jf, DEFAULT_VEH_LENGTH_WITH_GAP, 1.);
574 // number of vehicles that fit into the NEXT queue (could be larger than expected with DEFAULT_VEH_LENGTH_WITH_GAP!)
575 const double headwayCapacity = MAX2(nextQueueSize, nextQueueCapacity / DEFAULT_VEH_LENGTH_WITH_GAP);
576 // number of vehicles above which the NEXT queue is jammed
577 const double n_jam_threshold = headwayCapacity * nextJamThreshold / nextQueueCapacity;
578
579 // slope a and axis offset b for the jam-jam headway function
580 // solving f(x) = a * x + b
581 const double a = (STEPS2TIME(myTau_jj) * headwayCapacity - STEPS2TIME(tau_jf_withLength)) / (headwayCapacity - n_jam_threshold);
582 const double b = headwayCapacity * (STEPS2TIME(myTau_jj) - a);
583
584 // it is only well defined for nextQueueSize >= n_jam_threshold (which may not be the case for longer vehicles), so we take the MAX
585 return TIME2STEPS(a * MAX2(nextQueueSize, n_jam_threshold) + b);
586}
587
588
589bool
593
594
595void
597 if (veh->getQueIndex() != PARKING_QUEUE) {
598 myQueues[veh->getQueIndex()].addReminders(veh);
599 }
600}
601
602
603void
604MESegment::receive(MEVehicle* veh, const int qIdx, SUMOTime time, const bool isDepart, const bool isTeleport, const bool newEdge) {
605 const double speed = isDepart ? -1 : MAX2(veh->getSpeed(), MESO_MIN_SPEED); // on the previous segment
606 veh->setSegment(this); // for arrival checking
607 veh->setLastEntryTime(time);
609 if (!isDepart && (
610 // arrival on entering a new edge
611 (newEdge && veh->moveRoutePointer())
612 // arrival on entering a new segment
613 || veh->hasArrived())) {
614 // route has ended
615 veh->setEventTime(time + TIME2STEPS(myLength / speed)); // for correct arrival speed
616 addReminders(veh);
618 veh->updateDetectors(time, true,
621 return;
622 }
623 assert(veh->getEdge() == &getEdge());
624 // route continues
625 Queue& q = myQueues[qIdx];
626 const double maxSpeedOnEdge = veh->getEdge()->getLanes()[qIdx]->getVehicleMaxSpeed(veh);
627 const double uspeed = MAX2(maxSpeedOnEdge, MESO_MIN_SPEED);
628 std::vector<MEVehicle*>& cars = q.getModifiableVehicles();
629 MEVehicle* newLeader = nullptr; // first vehicle in the current queue
630 const SUMOTime stopTime = veh->checkStop(time);
631 SUMOTime tleave = MAX2(stopTime + TIME2STEPS(myLength / uspeed) + getLinkPenalty(veh), q.getBlockTime());
632 if (veh->isStopped()) {
633 myEdge.addWaiting(veh);
634 }
635 if (veh->isParking()) {
636 // parking stops should take at least 1ms
637 veh->setEventTime(MAX2(stopTime, veh->getEventTime() + 1));
638 veh->setSegment(this, PARKING_QUEUE);
639 myEdge.getLanes()[0]->addParking(veh); // TODO for GUI only
640 } else {
641 myEdge.lock();
642 if (cars.empty()) {
643 cars.push_back(veh);
644 newLeader = veh;
645 } else {
646 SUMOTime leaderOut = cars[0]->getEventTime();
647 if (!isDepart && leaderOut > tleave && overtake()) {
648 if (cars.size() == 1) {
650 newLeader = veh;
651 }
652 cars.insert(cars.begin() + 1, veh);
653 } else {
654 tleave = MAX2(leaderOut + tauWithVehLength(myTau_ff, cars[0]->getVehicleType().getLengthWithGap(), cars[0]->getVehicleType().getCarFollowModel().getHeadwayTime()), tleave);
655 cars.insert(cars.begin(), veh);
656 }
657 }
658 myEdge.unlock();
660 if (!isDepart && !isTeleport) {
661 // departs and teleports could take place anywhere on the edge so they should not block regular flow
662 // the -1 facilitates interleaving of multiple streams
664 }
666 veh->setEventTime(tleave);
667 veh->setSegment(this, qIdx);
668 }
669 addReminders(veh);
670 if (isDepart) {
671 veh->onDepart();
673 } else if (newEdge) {
675 } else {
677 }
678 if (veh->isParking()) {
679 MSGlobals::gMesoNet->addLeaderCar(veh, nullptr);
680 } else {
681 if (newLeader != nullptr) {
682 MSGlobals::gMesoNet->addLeaderCar(newLeader, getLink(newLeader));
683 }
684 }
685}
686
687
688bool
690 for (const Queue& q : myQueues) {
691 if (q.size() > 0) {
692 for (MEVehicle* const veh : q.getVehicles()) {
693 if (filter->vehicleApplies(*veh)) {
696 return true;
697 }
698 }
699 }
700 }
701 return false;
702}
703
704
705void
706MESegment::setSpeedForQueue(double newSpeed, SUMOTime currentTime, SUMOTime blockTime, const std::vector<MEVehicle*>& vehs) {
707 MEVehicle* v = vehs.back();
708 v->updateDetectors(currentTime, false);
709 SUMOTime newEvent = MAX2(newArrival(v, newSpeed, currentTime), blockTime);
710 if (v->getEventTime() != newEvent) {
712 v->setEventTime(newEvent);
714 }
715 for (std::vector<MEVehicle*>::const_reverse_iterator i = vehs.rbegin() + 1; i != vehs.rend(); ++i) {
716 (*i)->updateDetectors(currentTime, false);
717 newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + myTau_ff);
718 //newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + myTau_ff + (SUMOTime)((*(i - 1))->getVehicleType().getLength() / myTau_length));
719 (*i)->setEventTime(newEvent);
720 }
721}
722
723
725MESegment::newArrival(const MEVehicle* const v, double newSpeed, SUMOTime currentTime) {
726 // since speed is only an upper bound pos may be to optimistic
727 const double pos = MIN2(myLength, STEPS2TIME(currentTime - v->getLastEntryTime()) * v->getSpeed());
728 // traveltime may not be 0
729 double tt = (myLength - pos) / MAX2(newSpeed, MESO_MIN_SPEED);
730 return currentTime + MAX2(TIME2STEPS(tt), SUMOTime(1));
731}
732
733
734void
735MESegment::setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh, int qIdx) {
736 recomputeJamThreshold(jamThresh);
737 //myTau_length = MAX2(MESO_MIN_SPEED, newSpeed) * myEdge.getLanes().size() / TIME2STEPS(1);
738 int i = 0;
739 for (const Queue& q : myQueues) {
740 if (q.size() != 0) {
741 if (qIdx == -1 || qIdx == i) {
742 setSpeedForQueue(newSpeed, currentTime, q.getBlockTime(), q.getVehicles());
743 }
744 }
745 i++;
746 }
747}
748
749
752 SUMOTime result = SUMOTime_MAX;
753 for (const Queue& q : myQueues) {
754 if (q.size() != 0 && q.getVehicles().back()->getEventTime() < result) {
755 result = q.getVehicles().back()->getEventTime();
756 }
757 }
758 if (result < SUMOTime_MAX) {
759 return result;
760 }
761 return -1;
762}
763
764
765void
767 bool write = false;
768 for (const Queue& q : myQueues) {
769 if (q.getBlockTime() != -1 || !q.getVehicles().empty()) {
770 write = true;
771 break;
772 }
773 }
774 if (write) {
776 for (const Queue& q : myQueues) {
777 out.openTag(SUMO_TAG_VIEWSETTINGS_VEHICLES).writeAttr(SUMO_ATTR_TIME, toString<SUMOTime>(q.getBlockTime()));
778 out.writeAttr(SUMO_ATTR_VALUE, q.getVehicles());
779 out.closeTag();
780 }
781 out.closeTag();
782 }
783}
784
785
786void
788 for (Queue& q : myQueues) {
789 q.getModifiableVehicles().clear();
790 }
791}
792
793void
794MESegment::loadState(const std::vector<std::string>& vehIds, MSVehicleControl& vc, const SUMOTime block, const int queIdx) {
795 Queue& q = myQueues[queIdx];
796 for (const std::string& id : vehIds) {
797 MEVehicle* v = static_cast<MEVehicle*>(vc.getVehicle(id));
798 // vehicle could be removed due to options
799 if (v != nullptr) {
800 assert(v->getSegment() == this);
801 q.getModifiableVehicles().push_back(v);
804 }
805 }
806 if (q.size() != 0) {
807 // add the last vehicle of this queue
808 // !!! one question - what about the previously added vehicle? Is it stored twice?
809 MEVehicle* veh = q.getVehicles().back();
811 }
812 q.setBlockTime(block);
814}
815
816
817std::vector<const MEVehicle*>
819 std::vector<const MEVehicle*> result;
820 for (const Queue& q : myQueues) {
821 result.insert(result.end(), q.getVehicles().begin(), q.getVehicles().end());
822 }
823 return result;
824}
825
826
827bool
829 for (const Queue& q : myQueues) {
830 if (q.size() > 0 && q.getVehicles().back()->getWaitingTime() > 0) {
831 return true;
832 }
833 }
834 return false;
835}
836
837
838double
840 return 3600 * getCarNumber() * getMeanSpeed() / myLength;
841}
842
843
846 const MSLink* link = getLink(veh, myTLSPenalty || myCheckMinorPenalty);
847 if (link != nullptr) {
848 SUMOTime result = 0;
849 if (link->isTLSControlled()) {
850 result += link->getMesoTLSPenalty();
851 }
852 // minor tls links may get an additional penalty
853 if (!link->havePriority() &&
854 // do not apply penalty on top of tLSPenalty
855 !myTLSPenalty &&
856 // do not apply penalty if limited control is active
858 result += myMinorPenalty;
859 }
860 return result;
861 } else {
862 return 0;
863 }
864}
865
866
867double
869 double result = 0;
870 for (const Queue& q : myQueues) {
871 // @note: only the leader currently accumulates waitingTime but this might change in the future
872 for (const MEVehicle* veh : q.getVehicles()) {
873 result += veh->getWaitingSeconds();
874 }
875 }
876 return result;
877}
878
879
880/****************************************************************************/
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_COND2(obj)
Definition MESegment.cpp:52
#define STEPS2TIME(x)
Definition SUMOTime.h:55
#define SUMOTime_MAX
Definition SUMOTime.h:34
#define SUMOTime_MIN
Definition SUMOTime.h:35
#define SIMTIME
Definition SUMOTime.h:62
#define TIME2STEPS(x)
Definition SUMOTime.h:57
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
SUMOVehicleClass
Definition of vehicle classes to differ between different lane usage and authority types.
@ 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:37
T MIN2(T a, T b)
Definition StdDefs.h:76
T MAX2(T a, T b)
Definition StdDefs.h:82
T MAX3(T a, T b, T c)
Definition StdDefs.h:96
static bool isEnteringRoundabout(const MSEdge &e)
whether the given edge is entering a roundabout
Definition MELoop.cpp:357
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:340
bool removeLeaderCar(MEVehicle *v)
Removes the given car from the leading vehicles.
Definition MELoop.cpp:251
void addLeaderCar(MEVehicle *veh, MSLink *link)
Adds the given car to the leading vehicles.
Definition MELoop.cpp:238
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:125
bool allows(SUMOVehicleClass vclass) const
Definition MESegment.h:89
std::vector< MEVehicle * > & getModifiableVehicles()
Definition MESegment.h:80
void addReminders(MEVehicle *veh) const
Definition MESegment.cpp:92
void addDetector(MSMoveReminder *data)
Definition MESegment.cpp:84
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:122
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
double myQueueCapacity
The number of lanes represented by the queue * the length of the lane.
Definition MESegment.h:553
bool overtake()
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:507
SUMOTime myTau_ff
The time headway parameters, see the Eissfeldt thesis.
Definition MESegment.h:530
bool initialise(MEVehicle *veh, SUMOTime time)
Inserts (emits) vehicle into the segment.
std::vector< Queue > myQueues
The car queues. Vehicles are inserted in the front and removed in the back.
Definition MESegment.h:559
double getBruttoOccupancy() const
Returns the occupany of the segment (the sum of the vehicle lengths + minGaps)
Definition MESegment.h:258
SUMOTime myLastHeadway
the last headway
Definition MESegment.h:568
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
bool isOpen(const MEVehicle *veh) const
Returns whether the vehicle may use the next link.
void addDetector(MSMoveReminder *data, int queueIndex=-1)
Adds a data collector for a detector to this segment.
void clearState()
Remove all vehicles before quick-loading state.
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.
SUMOTime getLinkPenalty(const MEVehicle *veh) const
Returns the penalty time for passing a link (if using gMesoTLSPenalty > 0 or gMesoMinorPenalty > 0)
void writeVehicles(OutputDevice &of) const
std::map< const MSEdge *, int > myFollowerMap
The follower edge to allowed que index mapping for multi queue segments.
Definition MESegment.h:565
MSLink * getLink(const MEVehicle *veh, bool tlsPenalty=false) const
Returns the link the given car will use when passing the next junction.
int myNumVehicles
The cached value for the number of vehicles.
Definition MESegment.h:562
void setSpeedForQueue(double newSpeed, SUMOTime currentTime, SUMOTime blockTime, const std::vector< MEVehicle * > &vehs)
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.
void updatePermissions()
called when permissions change due to Rerouter or TraCI
void saveState(OutputDevice &out) const
Saves the state of this segment into the given stream.
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)
const MSEdge & getEdge() const
Returns the edge this segment belongs to.
Definition MESegment.h:359
static MESegment myVaporizationTarget
Definition MESegment.h:573
double myJamThreshold
The space (in m) which needs to be occupied before the segment is considered jammed.
Definition MESegment.h:556
const int myIndex
Running number of the segment in the edge.
Definition MESegment.h:524
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.
SUMOTime myMinorPenalty
Definition MESegment.h:537
double myMeanSpeed
the mean speed on this segment. Updated at event time or on demand
Definition MESegment.h:576
bool myCheckMinorPenalty
penalty for minor links
Definition MESegment.h:536
double jamThresholdForSpeed(double speed, double jamThresh) const
compute jam threshold for the given speed and jam-threshold option
SUMOTime myLastMeanSpeedUpdate
the time at which myMeanSpeed was last updated
Definition MESegment.h:579
SUMOTime myTau_jf
Definition MESegment.h:530
void setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh=DO_NOT_PATCH_JAM_THRESHOLD, int qIdx=-1)
reset mySpeed and patch the speed of all vehicles in it. Also set/recompute myJamThreshold
MESegment * myNextSegment
The next segment of this edge, 0 if this is the last segment of this edge.
Definition MESegment.h:518
bool hasBlockedLeader() const
whether a leader in any queue is blocked
double getWaitingSeconds() const
Get the waiting time for vehicles in all queues.
const double myLength
The segment's length.
Definition MESegment.h:521
SUMOTime getEventTime() const
Returns the (planned) time at which the next vehicle leaves this segment.
const MSEdge & myEdge
The microsim edge this segment belongs to.
Definition MESegment.h:515
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
MEVehicle * removeCar(MEVehicle *v, SUMOTime leaveTime, const MSMoveReminder::Notification reason)
Removes the given car from the edge's que.
std::vector< const MEVehicle * > getVehicles() const
returns all vehicles (for debugging)
static MSEdge myDummyParent
Definition MESegment.h:572
void recomputeJamThreshold(double jamThresh)
compute a value for myJamThreshold if jamThresh is negative, compute a value which allows free flow a...
double getMeanSpeed() const
wrapper to satisfy the FunctionBinding signature
Definition MESegment.h:294
int getCarNumber() const
Returns the total number of cars on the segment.
Definition MESegment.h:206
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.
double myTau_length
Headway parameter for computing gross time headyway from net time headway, length and edge speed.
Definition MESegment.h:547
SUMOTime myTau_jj
Definition MESegment.h:530
SUMOTime newArrival(const MEVehicle *const v, double newSpeed, SUMOTime currentTime)
compute the new arrival time when switching speed
bool myJunctionControl
Whether junction control is enabled.
Definition MESegment.h:540
bool myTLSPenalty
Whether tls penalty is enabled.
Definition MESegment.h:533
static const double DO_NOT_PATCH_JAM_THRESHOLD
Definition MESegment.h:51
double getFlow() const
returns flow based on headway
static bool isInvalid(const MESegment *segment)
whether the given segment is 0 or encodes vaporization
Definition MESegment.h:443
SUMOTime getNextInsertionTime(SUMOTime earliestEntry) const
return a time after earliestEntry at which a vehicle may be inserted at full speed
double myCapacity
The number of lanes represented by the queue * the length of the lane.
Definition MESegment.h:550
bool myOvertaking
Whether overtaking is permitted on this segment.
Definition MESegment.h:543
void prepareDetectorForWriting(MSMoveReminder &data, int queueIndex=-1)
Removes a data collector for a detector from this segment.
bool vaporizeAnyCar(SUMOTime currentTime, const MSDetectorFileOutput *filter)
tries to remove any car from this segment
SUMOTime myTau_fj
Definition MESegment.h:530
SUMOTime getTauJJ(double nextQueueSize, double nextQueueCapacity, double nextJamThreshold) const
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 across the link.
void processStop()
ends the current stop and performs loading/unloading
SUMOTime getWaitingTime(const bool accumulated=false) const
Returns the duration for which the vehicle was blocked.
Definition MEVehicle.h:284
bool hasArrived() const
Returns whether this vehicle has already arrived (reached the arrivalPosition on its final edge)
bool moveRoutePointer()
Update when the vehicle enters a new edge in the move step.
SUMOTime checkStop(SUMOTime time)
Returns until when to stop at the current segment and sets the information that the stop has been rea...
void updateDetectors(SUMOTime currentTime, const bool isLeave, const MSMoveReminder::Notification reason=MSMoveReminder::NOTIFICATION_JUNCTION)
Updates all vehicle detectors.
SUMOTime getLastEntryTime() const
Returns the time the vehicle entered the current segment.
Definition MEVehicle.h:255
void setEventTime(SUMOTime t, bool hasDelay=true)
Sets the (planned) time at which the vehicle leaves its current segment.
Definition MEVehicle.h:194
MESegment * getSegment() const
Returns the current segment the vehicle is on.
Definition MEVehicle.h:224
void setLastEntryTime(SUMOTime t)
Sets the entry time for the current segment.
Definition MEVehicle.h:247
int getQueIndex() const
Returns the index of the que the vehicle is in.
Definition MEVehicle.h:233
virtual void setSegment(MESegment *s, int idx=0)
Sets the current segment the vehicle is at together with its que.
Definition MEVehicle.h:215
SUMOTime getEventTime() const
Returns the (planned) time at which the vehicle leaves its current segment.
Definition MEVehicle.h:206
void setBlockTime(const SUMOTime t)
Sets the time at which the vehicle was blocked.
Definition MEVehicle.h:269
double getSpeed() const
Returns the vehicle's estimated speed assuming no delays.
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 hasValidRoute(std::string &msg, ConstMSRoutePtr route=0) const
Validates the current or given route.
bool isParking() const
Returns whether the vehicle is parking.
const MSEdge * getEdge() const
Returns the edge the vehicle is currently at.
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:264
virtual double getHeadwayTime() const
Get the driver's desired headway [s].
Definition MSCFModel.h:311
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:777
SVCPermissions getPermissions() const
Returns the combined permissions of all lanes of this edge.
Definition MSEdge.h:649
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, bool ignoreTransientPermissions=false) const
Get the allowed lanes to reach the destination-edge.
Definition MSEdge.cpp:479
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:1158
const MSJunction * getToJunction() const
Definition MSEdge.h:418
static SVCPermissions getMesoPermissions(SVCPermissions p, SVCPermissions ignoreIgnored=0)
Definition MSEdge.cpp:315
bool isRoundabout() const
Definition MSEdge.h:721
bool isVaporizing() const
Returns whether vehicles on this edge shall be vaporized.
Definition MSEdge.h:434
void addWaiting(SUMOVehicle *vehicle) const
Adds a vehicle to the list of waiting vehicles.
Definition MSEdge.cpp:1451
bool hasMinorLink() const
whether any lane has a minor link
Definition MSEdge.cpp:1350
virtual void lock() const
grant exclusive access to the mesoscopic state
Definition MSEdge.h:774
const MSEdgeVector & getSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges, restricted by vClass.
Definition MSEdge.cpp:1258
static bool gCheckRoutes
Definition MSGlobals.h:91
static MELoop * gMesoNet
mesoscopic simulation infrastructure
Definition MSGlobals.h:112
static bool gMesoLimitedJunctionControl
Definition MSGlobals.h:109
SumoXMLNodeType getType() const
return the type of this Junction
Definition MSJunction.h:133
Representation of a lane in the micro simulation.
Definition MSLane.h:84
MSEdge & getEdge() const
Returns the lane's edge.
Definition MSLane.h:764
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:724
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:186
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:320
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition MSNet.h:378
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.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
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)
#define DEBUG_COND
edge type specific meso parameters
Definition MESegment.h:55