1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file MESegment.cpp
11 /// @author Daniel Krajzewicz
12 /// @date Tue, May 2005
13 /// @version $Id$
14 ///
15 // A single mesoscopic segment (cell)
16 /****************************************************************************/
17
18
19 // ===========================================================================
20 // included modules
21 // ===========================================================================
22 #include <config.h>
23
24 #include <algorithm>
25 #include <limits>
26 #include <utils/common/StdDefs.h>
27 #include <microsim/MSGlobals.h>
28 #include <microsim/MSEdge.h>
29 #include <microsim/MSJunction.h>
30 #include <microsim/MSNet.h>
31 #include <microsim/MSLane.h>
32 #include <microsim/MSLinkCont.h>
33 #include <microsim/MSVehicle.h>
34 #include <microsim/MSMoveReminder.h>
35 #include <microsim/output/MSXMLRawOut.h>
36 #include <microsim/MSVehicleControl.h>
37 #include <microsim/devices/MSDevice.h>
38 #include <utils/common/FileHelpers.h>
39 #include <utils/iodevices/BinaryInputDevice.h>
40 #include <utils/iodevices/OutputDevice.h>
41 #include <utils/common/RandHelper.h>
42 #include "MEVehicle.h"
43 #include "MELoop.h"
44 #include "MESegment.h"
45
46 #define DEFAULT_VEH_LENGHT_WITH_GAP (SUMOVTypeParameter::getDefault().length + SUMOVTypeParameter::getDefault().minGap)
47 // avoid division by zero when driving very slowly
48 #define MESO_MIN_SPEED (0.05)
49
50 //#define DEBUG_OPENED
51 //#define DEBUG_JAMTHRESHOLD
52 //#define DEBUG_COND (getID() == "blocker")
53 //#define DEBUG_COND (true)
54 #define DEBUG_COND (myEdge.isSelected())
55 #define DEBUG_COND2(obj) ((obj != 0 && (obj)->isSelected()))
56
57 // ===========================================================================
58 // static member defintion
59 // ===========================================================================
60 MSEdge MESegment::myDummyParent("MESegmentDummyParent", -1, EDGEFUNC_UNKNOWN, "", "", -1);
61 MESegment MESegment::myVaporizationTarget("vaporizationTarget");
62 const double MESegment::DO_NOT_PATCH_JAM_THRESHOLD(std::numeric_limits<double>::max());
63
64 // ===========================================================================
65 // method definitions
66 // ===========================================================================
MESegment(const std::string & id,const MSEdge & parent,MESegment * next,double length,double speed,int idx,SUMOTime tauff,SUMOTime taufj,SUMOTime taujf,SUMOTime taujj,double jamThresh,bool multiQueue,bool junctionControl)67 MESegment::MESegment(const std::string& id,
68 const MSEdge& parent, MESegment* next,
69 double length, double speed,
70 int idx,
71 SUMOTime tauff, SUMOTime taufj,
72 SUMOTime taujf, SUMOTime taujj,
73 double jamThresh, bool multiQueue, bool junctionControl) :
74 Named(id), myEdge(parent), myNextSegment(next),
75 myLength(length), myIndex(idx),
76 myTau_ff((SUMOTime)(tauff / parent.getLanes().size())),
77 myTau_fj((SUMOTime)(taufj / parent.getLanes().size())), // Eissfeldt p. 90 and 151 ff.
78 myTau_jf((SUMOTime)(taujf / parent.getLanes().size())),
79 myTau_jj((SUMOTime)(taujj / parent.getLanes().size())),
80 myTau_length(MAX2(MESO_MIN_SPEED, speed) * parent.getLanes().size() / TIME2STEPS(1)),
81 myHeadwayCapacity(length / DEFAULT_VEH_LENGHT_WITH_GAP * parent.getLanes().size())/* Eissfeldt p. 69 */,
82 myCapacity(length * parent.getLanes().size()),
83 myOccupancy(0.f),
84 myJunctionControl(junctionControl),
85 myTLSPenalty(MSGlobals::gMesoTLSPenalty > 0 &&
86 // only apply to the last segment of a tls-controlled edge
87 myNextSegment == nullptr && (
88 parent.getToJunction()->getType() == NODETYPE_TRAFFIC_LIGHT ||
89 parent.getToJunction()->getType() == NODETYPE_TRAFFIC_LIGHT_NOJUNCTION ||
90 parent.getToJunction()->getType() == NODETYPE_TRAFFIC_LIGHT_RIGHT_ON_RED)),
91 myMinorPenalty(MSGlobals::gMesoMinorPenalty > 0 &&
92 // only apply to the last segment of an uncontrolled edge that has at least 1 minor link
93 myNextSegment == nullptr &&
94 parent.getToJunction()->getType() != NODETYPE_TRAFFIC_LIGHT &&
95 parent.getToJunction()->getType() != NODETYPE_TRAFFIC_LIGHT_NOJUNCTION &&
96 parent.getToJunction()->getType() != NODETYPE_TRAFFIC_LIGHT_RIGHT_ON_RED &&
97 parent.hasMinorLink()),
98 myNumCars(0),
99 myEntryBlockTime(SUMOTime_MIN),
100 myLastHeadway(TIME2STEPS(-1)),
101 myMeanSpeed(speed),
102 myLastMeanSpeedUpdate(SUMOTime_MIN) {
103 myCarQues.push_back(std::vector<MEVehicle*>());
104 myBlockTimes.push_back(-1);
105 if (useMultiQueue(multiQueue, parent)) {
106 const std::vector<MSLane*>& lanes = parent.getLanes();
107 while (myCarQues.size() < lanes.size()) {
108 myCarQues.push_back(std::vector<MEVehicle*>());
109 myBlockTimes.push_back(-1);
110 }
111 for (int i = 0; i < (int)parent.getNumSuccessors(); ++i) {
112 const MSEdge* const edge = parent.getSuccessors()[i];
113 const std::vector<MSLane*>* const allowed = parent.allowedLanes(*edge);
114 assert(allowed != 0);
115 assert(allowed->size() > 0);
116 for (std::vector<MSLane*>::const_iterator j = allowed->begin(); j != allowed->end(); ++j) {
117 std::vector<MSLane*>::const_iterator it = std::find(lanes.begin(), lanes.end(), *j);
118 myFollowerMap[edge].push_back((int)distance(lanes.begin(), it));
119 }
120 }
121 }
122 recomputeJamThreshold(jamThresh);
123 }
124
125
MESegment(const std::string & id)126 MESegment::MESegment(const std::string& id):
127 Named(id),
128 myEdge(myDummyParent), // arbitrary edge needed to supply the needed reference
129 myNextSegment(nullptr), myLength(0), myIndex(0),
130 myTau_ff(0), myTau_fj(0), myTau_jf(0), myTau_jj(0), myTau_length(1),
131 myHeadwayCapacity(0), myCapacity(0), myJunctionControl(false),
132 myTLSPenalty(false),
133 myMinorPenalty(false) {
134 }
135
136
137 bool
useMultiQueue(bool multiQueue,const MSEdge & parent)138 MESegment::useMultiQueue(bool multiQueue, const MSEdge& parent) {
139 return multiQueue && parent.getLanes().size() > 1 && parent.getNumSuccessors() > 1;
140 }
141
142 void
recomputeJamThreshold(double jamThresh)143 MESegment::recomputeJamThreshold(double jamThresh) {
144 if (jamThresh == DO_NOT_PATCH_JAM_THRESHOLD) {
145 return;
146 }
147 if (jamThresh < 0) {
148 // compute based on speed
149 double speed = myEdge.getSpeedLimit();
150 if (myTLSPenalty || myMinorPenalty) {
151 double travelTime = myLength / MAX2(speed, NUMERICAL_EPS) + getMaxPenaltySeconds();
152 speed = myLength / travelTime;
153 }
154 myJamThreshold = jamThresholdForSpeed(speed, jamThresh);
155 } else {
156 // compute based on specified percentage
157 myJamThreshold = jamThresh * myCapacity;
158 }
159
160 // update coefficients for the jam-jam headway function
161 // this function models the effect that "empty space" needs to move
162 // backwards through the downstream segment before the upstream segment may
163 // send annother vehicle.
164 // this allows jams to clear and move upstream.
165 // the headway function f(x) depends on the number of vehicles in the
166 // downstream segment x
167 // f is a linear function that passes through the following fixed points:
168 // f(n_jam_threshold) = tau_jf_withLength (for continuity)
169 // f(myHeadwayCapacity) = myTau_jj * myHeadwayCapacity
170
171 const SUMOTime tau_jf_withLength = tauWithVehLength(myTau_jf, DEFAULT_VEH_LENGHT_WITH_GAP);
172 if (myJamThreshold < myCapacity) {
173 // jamming is possible
174 const double n_jam_threshold = myHeadwayCapacity * myJamThreshold / myCapacity; // number of vehicles above which the segment is jammed
175 // solving f(x) = a * x + b
176 myA = (STEPS2TIME(myTau_jj) * myHeadwayCapacity - STEPS2TIME(tau_jf_withLength)) / (myHeadwayCapacity - n_jam_threshold);
177 myB = myHeadwayCapacity * (STEPS2TIME(myTau_jj) - myA);
178
179 // note that the original Eissfeldt model (p. 69) used different fixed points
180 // f(n_jam_threshold) = n_jam_threshold * myTau_jj
181 // f(myHeadwayCapacity) = myTau_jf * myHeadwayCapacity
182 //
183 // However, this systematically underestimates the backpropagation speed of the jam front (see #2244)
184 } else {
185 // dummy values. Should not be used
186 myA = 0;
187 myB = STEPS2TIME(tau_jf_withLength);
188 }
189 }
190
191
192 double
jamThresholdForSpeed(double speed,double jamThresh) const193 MESegment::jamThresholdForSpeed(double speed, double jamThresh) const {
194 // vehicles driving freely at maximum speed should not jam
195 // we compute how many vehicles could possible enter the segment until the first vehicle leaves
196 // and multiply by the space these vehicles would occupy
197 // the jamThresh parameter is scale the resulting value
198 if (speed == 0) {
199 return std::numeric_limits<double>::max(); // never jam. Irrelevant at speed 0 anyway
200 }
201 #ifdef DEBUG_JAMTHRESHOLD
202 if (true || DEBUG_COND) {
203 std::cout << "jamThresholdForSpeed seg=" << getID() << " speed=" << speed << " jamThresh=" << jamThresh << " ffVehs=" << std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGHT_WITH_GAP)))) << " thresh=" << std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGHT_WITH_GAP)))) * DEFAULT_VEH_LENGHT_WITH_GAP
204 << "\n";
205 }
206 #endif
207 return std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGHT_WITH_GAP)))) * DEFAULT_VEH_LENGHT_WITH_GAP;
208 }
209
210
211 void
addDetector(MSMoveReminder * data)212 MESegment::addDetector(MSMoveReminder* data) {
213 myDetectorData.push_back(data);
214 for (Queues::const_iterator k = myCarQues.begin(); k != myCarQues.end(); ++k) {
215 for (std::vector<MEVehicle*>::const_reverse_iterator i = k->rbegin(); i != k->rend(); ++i) {
216 (*i)->addReminder(data);
217 }
218 }
219 }
220
221
222 void
removeDetector(MSMoveReminder * data)223 MESegment::removeDetector(MSMoveReminder* data) {
224 std::vector<MSMoveReminder*>::iterator it = std::find(
225 myDetectorData.begin(), myDetectorData.end(), data);
226 if (it != myDetectorData.end()) {
227 myDetectorData.erase(it);
228 }
229 for (Queues::const_iterator k = myCarQues.begin(); k != myCarQues.end(); ++k) {
230 for (std::vector<MEVehicle*>::const_reverse_iterator i = k->rbegin(); i != k->rend(); ++i) {
231 (*i)->removeReminder(data);
232 }
233 }
234 }
235
236
237 void
prepareDetectorForWriting(MSMoveReminder & data)238 MESegment::prepareDetectorForWriting(MSMoveReminder& data) {
239 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
240 for (Queues::const_iterator k = myCarQues.begin(); k != myCarQues.end(); ++k) {
241 SUMOTime earliestExitTime = currentTime;
242 for (std::vector<MEVehicle*>::const_reverse_iterator i = k->rbegin(); i != k->rend(); ++i) {
243 const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
244 (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
245 earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap());
246 }
247 }
248 }
249
250
251 bool
hasSpaceFor(const MEVehicle * veh,SUMOTime entryTime,bool init) const252 MESegment::hasSpaceFor(const MEVehicle* veh, SUMOTime entryTime, bool init) const {
253 if (myOccupancy == 0.) {
254 // we have always space for at least one vehicle
255 return true;
256 }
257 const double newOccupancy = myOccupancy + veh->getVehicleType().getLengthWithGap();
258 if (newOccupancy > myCapacity) {
259 // we must ensure that occupancy remains below capacity
260 return false;
261 }
262 // regular insertions and initial insertions must respect different constraints:
263 // - regular insertions must respect entryBlockTime
264 // - initial insertions should not cause additional jamming
265 // - inserted vehicle should be able to continue at the current speed
266 if (init) {
267 if (free() && !hasBlockedLeader()) {
268 return newOccupancy <= myJamThreshold;
269 } else {
270 return newOccupancy <= jamThresholdForSpeed(getMeanSpeed(false), -1);
271 }
272 }
273 // maintain propper spacing between inflow from different lanes
274 return entryTime >= myEntryBlockTime;
275 }
276
277
278 bool
initialise(MEVehicle * veh,SUMOTime time)279 MESegment::initialise(MEVehicle* veh, SUMOTime time) {
280 if (hasSpaceFor(veh, time, true)) {
281 receive(veh, time, true);
282 // we can check only after insertion because insertion may change the route via devices
283 std::string msg;
284 if (MSGlobals::gCheckRoutes && !veh->hasValidRoute(msg)) {
285 throw ProcessError("Vehicle '" + veh->getID() + "' has no valid route. " + msg);
286 }
287 return true;
288 }
289 return false;
290 }
291
292
293 double
getMeanSpeed(bool useCached) const294 MESegment::getMeanSpeed(bool useCached) const {
295 const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
296 if (currentTime != myLastMeanSpeedUpdate || !useCached) {
297 myLastMeanSpeedUpdate = currentTime;
298 const SUMOTime tau = free() ? myTau_ff : myTau_jf;
299 double v = 0;
300 int count = 0;
301 for (Queues::const_iterator k = myCarQues.begin(); k != myCarQues.end(); ++k) {
302 SUMOTime earliestExitTime = currentTime;
303 count += (int)k->size();
304 for (std::vector<MEVehicle*>::const_reverse_iterator veh = k->rbegin(); veh != k->rend(); ++veh) {
305 v += (*veh)->getConservativeSpeed(earliestExitTime); // earliestExitTime is updated!
306 earliestExitTime += tauWithVehLength(tau, (*veh)->getVehicleType().getLengthWithGap());
307 }
308 }
309 if (count == 0) {
310 myMeanSpeed = myEdge.getSpeedLimit();
311 } else {
312 myMeanSpeed = v / (double) count;
313 }
314 }
315 return myMeanSpeed;
316 }
317
318
319 void
writeVehicles(OutputDevice & of) const320 MESegment::writeVehicles(OutputDevice& of) const {
321 for (Queues::const_iterator k = myCarQues.begin(); k != myCarQues.end(); ++k) {
322 for (std::vector<MEVehicle*>::const_iterator veh = k->begin(); veh != k->end(); ++veh) {
323 MSXMLRawOut::writeVehicle(of, *(*veh));
324 }
325 }
326 }
327
328
329 MEVehicle*
removeCar(MEVehicle * v,SUMOTime leaveTime,const MSMoveReminder::Notification reason)330 MESegment::removeCar(MEVehicle* v, SUMOTime leaveTime, const MSMoveReminder::Notification reason) {
331 myOccupancy = MAX2(0., myOccupancy - v->getVehicleType().getLengthWithGap());
332 std::vector<MEVehicle*>& cars = myCarQues[v->getQueIndex()];
333 assert(std::find(cars.begin(), cars.end(), v) != cars.end());
334 // One could be tempted to do v->setSegment(next); here but position on lane will be invalid if next == 0
335 v->updateDetectors(leaveTime, true, reason);
336 myNumCars--;
337 myEdge.lock();
338 if (v == cars.back()) {
339 cars.pop_back();
340 if (!cars.empty()) {
341 myEdge.unlock();
342 return cars.back();
343 }
344 } else {
345 cars.erase(std::find(cars.begin(), cars.end(), v));
346 }
347 myEdge.unlock();
348 return nullptr;
349 }
350
351
352 SUMOTime
getTimeHeadway(const MESegment * pred,const MEVehicle * veh)353 MESegment::getTimeHeadway(const MESegment* pred, const MEVehicle* veh) {
354 const SUMOTime tau = (pred->free()
355 ? (free() ? myTau_ff : myTau_fj)
356 : (free() ? myTau_jf : TIME2STEPS(myA * getCarNumber() + myB)));
357 return (SUMOTime)(tauWithVehLength(tau, veh->getVehicleType().getLengthWithGap()) / pred->getTLSCapacity(veh));
358 }
359
360
361 SUMOTime
getNextInsertionTime(SUMOTime earliestEntry) const362 MESegment::getNextInsertionTime(SUMOTime earliestEntry) const {
363 // since we do not know which queue will be used we give a conservative estimate
364 SUMOTime earliestLeave = earliestEntry;
365 for (int i = 0; i < (int)myCarQues.size(); ++i) {
366 earliestLeave = MAX2(earliestLeave, myBlockTimes[i]);
367 }
368 if (myEdge.getSpeedLimit() == 0) {
369 return MAX2(earliestEntry, myEntryBlockTime); // FIXME: This line is just an adhoc-fix to avoid division by zero (Leo)
370 } else {
371 return MAX3(earliestEntry, earliestLeave - TIME2STEPS(myLength / myEdge.getSpeedLimit()), myEntryBlockTime);
372 }
373 }
374
375
376 MSLink*
getLink(const MEVehicle * veh,bool penalty) const377 MESegment::getLink(const MEVehicle* veh, bool penalty) const {
378 if (myJunctionControl || penalty) {
379 const MSEdge* const nextEdge = veh->succEdge(1);
380 if (nextEdge == nullptr) {
381 return nullptr;
382 }
383 // try to find any link leading to our next edge, start with the lane pointed to by the que index
384 const MSLane* const bestLane = myEdge.getLanes()[veh->getQueIndex()];
385 const MSLinkCont& links = bestLane->getLinkCont();
386 for (std::vector<MSLink*>::const_iterator j = links.begin(); j != links.end(); ++j) {
387 if (&(*j)->getLane()->getEdge() == nextEdge) {
388 return *j;
389 }
390 }
391 // this is for the non-multique case, maybe we should use caching here !!!
392 for (std::vector<MSLane*>::const_iterator l = myEdge.getLanes().begin(); l != myEdge.getLanes().end(); ++l) {
393 if ((*l) != bestLane) {
394 const MSLinkCont& links = (*l)->getLinkCont();
395 for (std::vector<MSLink*>::const_iterator j = links.begin(); j != links.end(); ++j) {
396 if (&(*j)->getLane()->getEdge() == nextEdge) {
397 return *j;
398 }
399 }
400 }
401 }
402 }
403 return nullptr;
404 }
405
406
407 bool
isOpen(const MEVehicle * veh) const408 MESegment::isOpen(const MEVehicle* veh) const {
409 #ifdef DEBUG_OPENED
410 if (DEBUG_COND || DEBUG_COND2(veh)) {
411 std::cout << SIMTIME << " opened seg=" << getID() << " veh=" << Named::getIDSecure(veh)
412 << " tlsPenalty=" << myTLSPenalty;
413 const MSLink* link = getLink(veh);
414 if (link == 0) {
415 std::cout << " link=0";
416 } else {
417 std::cout << " prio=" << link->havePriority()
418 << " override=" << limitedControlOverride(link)
419 << " isOpen=" << link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
420 veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
421 veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime())
422 << " et=" << veh->getEventTime()
423 << " v=" << veh->getSpeed()
424 << " vLeave=" << veh->estimateLeaveSpeed(link)
425 << " impatience=" << veh->getImpatience()
426 << " tWait=" << veh->getWaitingTime();
427 }
428 std::cout << "\n";
429 }
430 #endif
431 if (myTLSPenalty) {
432 // XXX should limited control take precedence over tls penalty?
433 return true;
434 }
435 const MSLink* link = getLink(veh);
436 return (link == nullptr
437 || link->havePriority()
438 || limitedControlOverride(link)
439 || link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
440 veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
441 veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime()));
442 }
443
444
445 bool
limitedControlOverride(const MSLink * link) const446 MESegment::limitedControlOverride(const MSLink* link) const {
447 assert(link != 0);
448 if (!MSGlobals::gMesoLimitedJunctionControl) {
449 return false;
450 }
451 // if the target segment of this link is not saturated junction control is disabled
452 const MSEdge& targetEdge = link->getLane()->getEdge();
453 const MESegment* target = MSGlobals::gMesoNet->getSegmentForEdge(targetEdge);
454 return (target->myOccupancy * 2 < target->myJamThreshold) && !targetEdge.isRoundabout();
455 }
456
457
458 void
send(MEVehicle * veh,MESegment * next,SUMOTime time,const MSMoveReminder::Notification reason)459 MESegment::send(MEVehicle* veh, MESegment* next, SUMOTime time, const MSMoveReminder::Notification reason) {
460 assert(isInvalid(next) || time >= myBlockTimes[veh->getQueIndex()]);
461 MSLink* link = getLink(veh);
462 if (link != nullptr) {
463 link->removeApproaching(veh);
464 }
465 MEVehicle* lc = removeCar(veh, time, reason); // new leaderCar
466 myBlockTimes[veh->getQueIndex()] = time;
467 if (!isInvalid(next)) {
468 myLastHeadway = next->getTimeHeadway(this, veh);
469 myBlockTimes[veh->getQueIndex()] += myLastHeadway;
470 }
471 if (lc != nullptr) {
472 lc->setEventTime(MAX2(lc->getEventTime(), myBlockTimes[veh->getQueIndex()]));
473 MSGlobals::gMesoNet->addLeaderCar(lc, getLink(lc));
474 }
475 if (veh->isStopped()) {
476 veh->processStop();
477 }
478 }
479
480 bool
overtake()481 MESegment::overtake() {
482 return MSGlobals::gMesoOvertaking && myCapacity > myLength && RandHelper::rand() > (myOccupancy / myCapacity);
483 }
484
485
486 void
addReminders(MEVehicle * veh) const487 MESegment::addReminders(MEVehicle* veh) const {
488 for (std::vector<MSMoveReminder*>::const_iterator i = myDetectorData.begin(); i != myDetectorData.end(); ++i) {
489 veh->addReminder(*i);
490 }
491 }
492
493 void
receive(MEVehicle * veh,SUMOTime time,bool isDepart,bool afterTeleport)494 MESegment::receive(MEVehicle* veh, SUMOTime time, bool isDepart, bool afterTeleport) {
495 const double speed = isDepart ? -1 : MAX2(veh->getSpeed(), MESO_MIN_SPEED); // on the previous segment
496 veh->setSegment(this); // for arrival checking
497 veh->setLastEntryTime(time);
498 veh->setBlockTime(SUMOTime_MAX);
499 if (!isDepart && (
500 // arrival on entering a new edge
501 ((myIndex == 0 || afterTeleport) && veh->moveRoutePointer())
502 // arrival on entering a new segment
503 || veh->hasArrived())) {
504 // route has ended
505 veh->setEventTime(time + TIME2STEPS(myLength / speed)); // for correct arrival speed
506 addReminders(veh);
507 veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
508 veh->updateDetectors(time, true, MSMoveReminder::NOTIFICATION_ARRIVED);
509 MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
510 return;
511 }
512 // route continues
513 const double maxSpeedOnEdge = veh->getEdge()->getVehicleMaxSpeed(veh);
514 const double uspeed = MAX2(maxSpeedOnEdge, MESO_MIN_SPEED);
515 int nextQueIndex = 0;
516 if (myCarQues.size() > 1) {
517 const MSEdge* succ = veh->succEdge(1);
518 // succ may be invalid if called from initialise() with an invalid route
519 if (succ != nullptr && myFollowerMap.count(succ) > 0) {
520 const std::vector<int>& indices = myFollowerMap[succ];
521 nextQueIndex = indices[0];
522 for (std::vector<int>::const_iterator i = indices.begin() + 1; i != indices.end(); ++i) {
523 if (myCarQues[*i].size() < myCarQues[nextQueIndex].size()) {
524 nextQueIndex = *i;
525 }
526 }
527 }
528 }
529 std::vector<MEVehicle*>& cars = myCarQues[nextQueIndex];
530 MEVehicle* newLeader = nullptr; // first vehicle in the current queue
531 SUMOTime tleave = MAX2(veh->getStoptime(this, time) + TIME2STEPS(myLength / uspeed) + getLinkPenalty(veh), myBlockTimes[nextQueIndex]);
532 if (veh->isStopped()) {
533 MSNet::getInstance()->getVehicleControl().addWaiting(&myEdge, veh);
534 }
535 myEdge.lock();
536 if (cars.empty()) {
537 cars.push_back(veh);
538 newLeader = veh;
539 } else {
540 SUMOTime leaderOut = cars[0]->getEventTime();
541 if (!isDepart && leaderOut > tleave && overtake()) {
542 if (cars.size() == 1) {
543 MSGlobals::gMesoNet->removeLeaderCar(cars[0]);
544 newLeader = veh;
545 }
546 cars.insert(cars.begin() + 1, veh);
547 } else {
548 tleave = MAX2(leaderOut + tauWithVehLength(myTau_ff, cars[0]->getVehicleType().getLengthWithGap()), tleave);
549 cars.insert(cars.begin(), veh);
550 }
551 }
552 myEdge.unlock();
553 myNumCars++;
554 if (!isDepart) {
555 // regular departs could take place anywhere on the edge so they should not block regular flow
556 // the -1 facilitates interleaving of multiple streams
557 myEntryBlockTime = time + tauWithVehLength(myTau_ff, veh->getVehicleType().getLengthWithGap()) - 1;
558 }
559 veh->setEventTime(tleave);
560 veh->setSegment(this, nextQueIndex);
561 myOccupancy = MIN2(myCapacity, myOccupancy + veh->getVehicleType().getLengthWithGap());
562 addReminders(veh);
563 if (isDepart) {
564 veh->onDepart();
565 veh->activateReminders(MSMoveReminder::NOTIFICATION_DEPARTED);
566 } else if (myIndex == 0 || afterTeleport) {
567 veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
568 } else {
569 veh->activateReminders(MSMoveReminder::NOTIFICATION_SEGMENT);
570 }
571 if (newLeader != nullptr) {
572 MSGlobals::gMesoNet->addLeaderCar(newLeader, getLink(newLeader));
573 }
574 }
575
576
577 bool
vaporizeAnyCar(SUMOTime currentTime)578 MESegment::vaporizeAnyCar(SUMOTime currentTime) {
579 MEVehicle* remove = nullptr;
580 for (Queues::const_iterator k = myCarQues.begin(); k != myCarQues.end(); ++k) {
581 if (!k->empty()) {
582 // remove last in queue
583 remove = k->front();
584 if (k->size() == 1) {
585 MSGlobals::gMesoNet->removeLeaderCar(remove);
586 }
587 MSGlobals::gMesoNet->changeSegment(remove, currentTime, &myVaporizationTarget);
588 return true;
589 }
590 }
591 return false;
592 }
593
594
595 void
setSpeedForQueue(double newSpeed,SUMOTime currentTime,SUMOTime blockTime,const std::vector<MEVehicle * > & vehs)596 MESegment::setSpeedForQueue(double newSpeed, SUMOTime currentTime, SUMOTime blockTime, const std::vector<MEVehicle*>& vehs) {
597 MEVehicle* v = vehs.back();
598 v->updateDetectors(currentTime, false);
599 SUMOTime newEvent = MAX2(newArrival(v, newSpeed, currentTime), blockTime);
600 if (v->getEventTime() != newEvent) {
601 MSGlobals::gMesoNet->removeLeaderCar(v);
602 v->setEventTime(newEvent);
603 MSGlobals::gMesoNet->addLeaderCar(v, getLink(v));
604 }
605 for (std::vector<MEVehicle*>::const_reverse_iterator i = vehs.rbegin() + 1; i != vehs.rend(); ++i) {
606 (*i)->updateDetectors(currentTime, false);
607 newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + myTau_ff);
608 //newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + myTau_ff + (SUMOTime)((*(i - 1))->getVehicleType().getLength() / myTau_length));
609 (*i)->setEventTime(newEvent);
610 }
611 }
612
613
614 SUMOTime
newArrival(const MEVehicle * const v,double newSpeed,SUMOTime currentTime)615 MESegment::newArrival(const MEVehicle* const v, double newSpeed, SUMOTime currentTime) {
616 // since speed is only an upper bound pos may be to optimistic
617 const double pos = MIN2(myLength, STEPS2TIME(currentTime - v->getLastEntryTime()) * v->getSpeed());
618 // traveltime may not be 0
619 return currentTime + MAX2(TIME2STEPS((myLength - pos) / newSpeed), SUMOTime(1));
620 }
621
622
623 void
setSpeed(double newSpeed,SUMOTime currentTime,double jamThresh)624 MESegment::setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh) {
625 recomputeJamThreshold(jamThresh);
626 //myTau_length = MAX2(MESO_MIN_SPEED, newSpeed) * myEdge.getLanes().size() / TIME2STEPS(1);
627 for (int i = 0; i < (int)myCarQues.size(); ++i) {
628 if (myCarQues[i].size() != 0) {
629 setSpeedForQueue(newSpeed, currentTime, myBlockTimes[i], myCarQues[i]);
630 }
631 }
632 }
633
634
635 SUMOTime
getEventTime() const636 MESegment::getEventTime() const {
637 SUMOTime result = SUMOTime_MAX;
638 for (int i = 0; i < (int)myCarQues.size(); ++i) {
639 if (myCarQues[i].size() != 0 && myCarQues[i].back()->getEventTime() < result) {
640 result = myCarQues[i].back()->getEventTime();
641 }
642 }
643 if (result < SUMOTime_MAX) {
644 return result;
645 }
646 return -1;
647 }
648
649
650 void
saveState(OutputDevice & out)651 MESegment::saveState(OutputDevice& out) {
652 out.openTag(SUMO_TAG_SEGMENT);
653 for (int i = 0; i < (int)myCarQues.size(); ++i) {
654 out.openTag(SUMO_TAG_VIEWSETTINGS_VEHICLES).writeAttr(SUMO_ATTR_TIME, toString<SUMOTime>(myBlockTimes[i]));
655 out.writeAttr(SUMO_ATTR_VALUE, myCarQues[i]);
656 out.closeTag();
657 }
658 out.closeTag();
659 }
660
661
662 void
loadState(const std::vector<std::string> & vehIds,MSVehicleControl & vc,const SUMOTime block,const int queIdx)663 MESegment::loadState(const std::vector<std::string>& vehIds, MSVehicleControl& vc, const SUMOTime block, const int queIdx) {
664 for (const std::string& id : vehIds) {
665 MEVehicle* v = static_cast<MEVehicle*>(vc.getVehicle(id));
666 // vehicle could be removed due to options
667 if (v != nullptr) {
668 assert(v->getSegment() == this);
669 myCarQues[queIdx].push_back(v);
670 myNumCars++;
671 myOccupancy += v->getVehicleType().getLengthWithGap();
672 }
673 }
674 if (myCarQues[queIdx].size() != 0) {
675 // add the last vehicle of this queue
676 // !!! one question - what about the previously added vehicle? Is it stored twice?
677 MEVehicle* veh = myCarQues[queIdx].back();
678 MSGlobals::gMesoNet->addLeaderCar(veh, getLink(veh));
679 }
680 myBlockTimes[queIdx] = block;
681 myOccupancy = MIN2(myCapacity, myOccupancy);
682 }
683
684
685 std::vector<const MEVehicle*>
getVehicles() const686 MESegment::getVehicles() const {
687 std::vector<const MEVehicle*> result;
688 for (Queues::const_iterator k = myCarQues.begin(); k != myCarQues.end(); ++k) {
689 result.insert(result.end(), k->begin(), k->end());
690 }
691 return result;
692 }
693
694
695 bool
hasBlockedLeader() const696 MESegment::hasBlockedLeader() const {
697 for (Queues::const_iterator k = myCarQues.begin(); k != myCarQues.end(); ++k) {
698 if (k->size() > 0 && (*k).back()->getWaitingTime() > 0) {
699 return true;
700 }
701 }
702 return false;
703 }
704
705
706 double
getFlow() const707 MESegment::getFlow() const {
708 return 3600 * getCarNumber() * getMeanSpeed() / myLength;
709 }
710
711
712 SUMOTime
getLinkPenalty(const MEVehicle * veh) const713 MESegment::getLinkPenalty(const MEVehicle* veh) const {
714 const MSLink* link = getLink(veh, myTLSPenalty || myMinorPenalty);
715 if (link != nullptr) {
716 SUMOTime result = 0;
717 if (link->isTLSControlled()) {
718 result += link->getMesoTLSPenalty();
719 }
720 // minor tls links may get an additional penalty
721 if (!link->havePriority() &&
722 // do not apply penalty if limited control is active
723 (!MSGlobals::gMesoLimitedJunctionControl || limitedControlOverride(link))) {
724 result += MSGlobals::gMesoMinorPenalty;
725 }
726 return result;
727 } else {
728 return 0;
729 }
730 }
731
732
733 double
getTLSCapacity(const MEVehicle * veh) const734 MESegment::getTLSCapacity(const MEVehicle* veh) const {
735 if (myTLSPenalty) {
736 const MSLink* link = getLink(veh, true);
737 if (link != nullptr) {
738 assert(link->isTLSControlled());
739 assert(link->getGreenFraction() > 0);
740 return link->getGreenFraction();
741 }
742 }
743 return 1;
744 }
745
746
747 double
getMaxPenaltySeconds() const748 MESegment::getMaxPenaltySeconds() const {
749 double maxPenalty = 0;
750 for (std::vector<MSLane*>::const_iterator i = myEdge.getLanes().begin(); i != myEdge.getLanes().end(); ++i) {
751 MSLane* l = *i;
752 const MSLinkCont& lc = l->getLinkCont();
753 for (MSLinkCont::const_iterator j = lc.begin(); j != lc.end(); ++j) {
754 MSLink* link = *j;
755 maxPenalty = MAX2(maxPenalty, STEPS2TIME(
756 link->getMesoTLSPenalty() + (link->havePriority() ? 0 : MSGlobals::gMesoMinorPenalty)));
757 }
758 }
759 return maxPenalty;
760 }
761
762 /****************************************************************************/
763