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