LCOV - code coverage report
Current view: top level - src/mesosim - MESegment.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 99.2 % 399 396
Test Date: 2026-07-26 16:30:20 Functions: 97.6 % 41 40

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    MESegment.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @date    Tue, May 2005
      17              : ///
      18              : // A single mesoscopic segment (cell)
      19              : /****************************************************************************/
      20              : #include <config.h>
      21              : 
      22              : #include <algorithm>
      23              : #include <limits>
      24              : #include <utils/common/StdDefs.h>
      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>
      31              : #include <microsim/MSMoveReminder.h>
      32              : #include <microsim/traffic_lights/MSTrafficLightLogic.h>
      33              : #include <microsim/traffic_lights/MSDriveWay.h>
      34              : #include <microsim/traffic_lights/MSRailSignalControl.h>
      35              : #include <microsim/output/MSXMLRawOut.h>
      36              : #include <microsim/output/MSDetectorFileOutput.h>
      37              : #include <microsim/MSVehicleControl.h>
      38              : #include <microsim/devices/MSDevice.h>
      39              : #include <utils/common/FileHelpers.h>
      40              : #include <utils/common/MsgHandler.h>
      41              : #include <utils/iodevices/OutputDevice.h>
      42              : #include <utils/common/RandHelper.h>
      43              : #include "MEVehicle.h"
      44              : #include "MELoop.h"
      45              : #include "MESegment.h"
      46              : 
      47              : #define DEFAULT_VEH_LENGTH_WITH_GAP (SUMOVTypeParameter::getDefault().length + SUMOVTypeParameter::getDefault().minGap)
      48              : // avoid division by zero when driving very slowly
      49              : #define MESO_MIN_SPEED (0.05)
      50              : 
      51              : //#define DEBUG_OPENED
      52              : //#define DEBUG_JAMTHRESHOLD
      53              : //#define DEBUG_COND (getID() == "blocker")
      54              : //#define DEBUG_COND (true)
      55              : #define DEBUG_COND (myEdge.isSelected())
      56              : #define DEBUG_COND2(obj) ((obj != 0 && (obj)->isSelected()))
      57              : 
      58              : 
      59              : // ===========================================================================
      60              : // static member definition
      61              : // ===========================================================================
      62              : MSEdge MESegment::myDummyParent("MESegmentDummyParent", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", "", -1, 0);
      63              : MESegment MESegment::myVaporizationTarget("vaporizationTarget");
      64              : const double MESegment::DO_NOT_PATCH_JAM_THRESHOLD(std::numeric_limits<double>::max());
      65              : const std::string MESegment::OVERRIDE_TLS_PENALTIES("meso.tls.control");
      66              : 
      67              : 
      68              : // ===========================================================================
      69              : // MESegment::Queue method definitions
      70              : // ===========================================================================
      71              : MEVehicle*
      72     26678510 : MESegment::Queue::remove(MEVehicle* v) {
      73     26678510 :     myOccupancy -= v->getVehicleType().getLengthWithGap();
      74              :     assert(std::find(myVehicles.begin(), myVehicles.end(), v) != myVehicles.end());
      75     26678510 :     if (v == myVehicles.back()) {
      76              :         myVehicles.pop_back();
      77     26672231 :         if (myVehicles.empty()) {
      78      8446821 :             myOccupancy = 0.;
      79              :         } else {
      80     18225410 :             return myVehicles.back();
      81              :         }
      82              :     } else {
      83         6279 :         myVehicles.erase(std::find(myVehicles.begin(), myVehicles.end(), v));
      84              :     }
      85              :     return nullptr;
      86              : }
      87              : 
      88              : void
      89       132203 : MESegment::Queue::addDetector(MSMoveReminder* data) {
      90       132203 :     myDetectorData.push_back(data);
      91       137953 :     for (MEVehicle* const v : myVehicles) {
      92         5750 :         v->addReminder(data);
      93              :     }
      94       132203 : }
      95              : 
      96              : void
      97     26720154 : MESegment::Queue::addReminders(MEVehicle* veh) const {
      98     36354252 :     for (MSMoveReminder* rem : myDetectorData) {
      99      9634098 :         veh->addReminder(rem);
     100              :     }
     101     26720154 : }
     102              : 
     103              : // ===========================================================================
     104              : // MESegment method definitions
     105              : // ===========================================================================
     106       726670 : MESegment::MESegment(const std::string& id,
     107              :                      const MSEdge& parent, MESegment* next,
     108              :                      const double length, const double speed,
     109              :                      const int idx,
     110              :                      const bool multiQueue,
     111       726670 :                      const MesoEdgeType& edgeType):
     112       726670 :     Named(id), myEdge(parent), myNextSegment(next),
     113       726670 :     myLength(length), myIndex(idx),
     114       726670 :     myTau_length(TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, speed)),
     115       726670 :     myNumVehicles(0),
     116       726670 :     myLastHeadway(TIME2STEPS(-1)),
     117       726670 :     myMeanSpeed(speed),
     118      1453013 :     myLastMeanSpeedUpdate(SUMOTime_MIN) {
     119              : 
     120              :     const std::vector<MSLane*>& lanes = parent.getLanes();
     121              :     int usableLanes = 0;
     122      1578603 :     for (MSLane* const l : lanes) {
     123       851933 :         const SVCPermissions allow = MSEdge::getMesoPermissions(l->getPermissions());
     124       851933 :         if (multiQueue) {
     125       111240 :             myQueues.push_back(Queue(allow));
     126              :         }
     127       851933 :         if (allow != 0) {
     128       798274 :             usableLanes++;
     129              :         }
     130              :     }
     131       726670 :     if (usableLanes == 0) {
     132              :         // cars won't drive here. Give sensible tau values capacity for the ignored classes
     133              :         usableLanes = 1;
     134              :     }
     135       726670 :     if (multiQueue) {
     136        23691 :         if (next == nullptr) {
     137       110079 :             for (const MSEdge* const edge : parent.getSuccessors()) {
     138        86733 :                 if (edge->isTazConnector()) {
     139          284 :                     continue;
     140              :                 }
     141        86449 :                 const std::vector<MSLane*>* const allowed = parent.allowedLanes(*edge);
     142              :                 assert(allowed != nullptr);
     143              :                 assert(allowed->size() > 0);
     144       180879 :                 for (MSLane* const l : *allowed) {
     145        94430 :                     std::vector<MSLane*>::const_iterator it = std::find(lanes.begin(), lanes.end(), l);
     146        94430 :                     myFollowerMap[edge] |= (1 << distance(lanes.begin(), it));
     147              :                 }
     148              :             }
     149              :         }
     150        23691 :         myQueueCapacity = length;
     151              :     } else {
     152      1405958 :         myQueues.push_back(Queue(parent.getPermissions()));
     153              :     }
     154              : 
     155       726670 :     initSegment(edgeType, parent, length * usableLanes);
     156       726670 : }
     157              : 
     158              : void
     159       726670 : MESegment::initSegment(const MesoEdgeType& edgeType, const MSEdge& parent, const double capacity) {
     160              : 
     161       726670 :     myCapacity = capacity;
     162       726670 :     if (myQueues.size() == 1) {
     163       703453 :         const double laneScale = capacity / myLength;
     164       703453 :         myQueueCapacity = capacity;
     165       703453 :         myTau_length = TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, myMeanSpeed) / laneScale;
     166              :         // Eissfeldt p. 90 and 151 ff.
     167       703453 :         myTau_ff = (SUMOTime)((double)edgeType.tauff / laneScale);
     168       703453 :         myTau_fj = (SUMOTime)((double)edgeType.taufj / laneScale);
     169       703453 :         myTau_jf = (SUMOTime)((double)edgeType.taujf / laneScale);
     170       703453 :         myTau_jj = (SUMOTime)((double)edgeType.taujj / laneScale);
     171              :     } else {
     172        23217 :         myTau_ff = edgeType.tauff;
     173        23217 :         myTau_fj = edgeType.taufj;
     174        23217 :         myTau_jf = edgeType.taujf;
     175        23217 :         myTau_jj = edgeType.taujj;
     176              :     }
     177              : 
     178       726670 :     myJunctionControl = myNextSegment == nullptr && (edgeType.junctionControl || MELoop::isEnteringRoundabout(parent));
     179       725894 :     myTLSPenalty = ((edgeType.tlsPenalty > 0 || edgeType.tlsFlowPenalty > 0) &&
     180              :                     // only apply to the last segment of a tls-controlled edge
     181       727030 :                     myNextSegment == nullptr && (
     182          298 :                         parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT ||
     183          298 :                         parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION ||
     184              :                         parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED));
     185              : 
     186              :     // only apply to the last segment of an uncontrolled edge that has at least 1 minor link
     187      1453660 :     myCheckMinorPenalty = (edgeType.minorPenalty > 0 &&
     188          320 :                            myNextSegment == nullptr &&
     189              :                            parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT &&
     190              :                            parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION &&
     191       726848 :                            parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
     192          178 :                            parent.hasMinorLink());
     193       726670 :     myMinorPenalty = edgeType.minorPenalty;
     194       726670 :     myOvertaking = edgeType.overtaking && myCapacity > myLength;
     195              : 
     196              :     //std::cout << getID() << " myMinorPenalty=" << myMinorPenalty << " myTLSPenalty=" << myTLSPenalty << " myJunctionControl=" << myJunctionControl << " myOvertaking=" << myOvertaking << "\n";
     197              : 
     198       726670 :     recomputeJamThreshold(edgeType.jamThreshold);
     199       726670 : }
     200              : 
     201        45570 : MESegment::MESegment(const std::string& id):
     202              :     Named(id),
     203        45570 :     myEdge(myDummyParent), // arbitrary edge needed to supply the needed reference
     204        45570 :     myNextSegment(nullptr), myLength(0), myIndex(0),
     205        45570 :     myTau_ff(0), myTau_fj(0), myTau_jf(0), myTau_jj(0),
     206        45570 :     myTLSPenalty(false),
     207        45570 :     myCheckMinorPenalty(false),
     208        45570 :     myMinorPenalty(0),
     209        45570 :     myJunctionControl(false),
     210        45570 :     myOvertaking(false),
     211        45570 :     myTau_length(1) {
     212        45570 : }
     213              : 
     214              : 
     215              : void
     216         2467 : MESegment::updatePermissions() {
     217         2467 :     if (myQueues.size() > 1) {
     218           64 :         for (MSLane* lane : myEdge.getLanes()) {
     219           48 :             myQueues[lane->getIndex()].setPermissions(lane->getPermissions());
     220              :         }
     221              :     } else {
     222         2451 :         myQueues.back().setPermissions(myEdge.getPermissions());
     223              :     }
     224         2467 : }
     225              : 
     226              : 
     227              : void
     228       727714 : MESegment::recomputeJamThreshold(double jamThresh) {
     229       727714 :     if (jamThresh == DO_NOT_PATCH_JAM_THRESHOLD) {
     230              :         return;
     231              :     }
     232       727714 :     if (jamThresh < 0) {
     233              :         // compute based on speed
     234       727702 :         myJamThreshold = jamThresholdForSpeed(myEdge.getSpeedLimit(), jamThresh);
     235              :     } else {
     236              :         // compute based on specified percentage
     237           12 :         myJamThreshold = jamThresh * myCapacity;
     238              :     }
     239              : }
     240              : 
     241              : 
     242              : double
     243      4954321 : MESegment::jamThresholdForSpeed(double speed, double jamThresh) const {
     244              :     // vehicles driving freely at maximum speed should not jam
     245              :     // we compute how many vehicles could possible enter the segment until the first vehicle leaves
     246              :     // and multiply by the space these vehicles would occupy
     247              :     // the jamThresh parameter is scale the resulting value
     248      4954321 :     if (speed == 0) {
     249              :         return std::numeric_limits<double>::max();  // never jam. Irrelevant at speed 0 anyway
     250              :     }
     251              : #ifdef DEBUG_JAMTHRESHOLD
     252              :     if (true || DEBUG_COND) {
     253              :         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
     254              :                   << "\n";
     255              :     }
     256              : #endif
     257      4954102 :     return std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGTH_WITH_GAP, 1.)))) * DEFAULT_VEH_LENGTH_WITH_GAP;
     258              : }
     259              : 
     260              : 
     261              : void
     262       128871 : MESegment::addDetector(MSMoveReminder* data, int queueIndex) {
     263       128871 :     if (queueIndex == -1) {
     264       254480 :         for (Queue& q : myQueues) {
     265       128906 :             q.addDetector(data);
     266              :         }
     267              :     } else {
     268              :         assert(queueIndex < (int)myQueues.size());
     269         3297 :         myQueues[queueIndex].addDetector(data);
     270              :     }
     271       128871 : }
     272              : 
     273              : 
     274              : /*
     275              : void
     276              : MESegment::removeDetector(MSMoveReminder* data) {
     277              :     std::vector<MSMoveReminder*>::iterator it = std::find(myDetectorData.begin(), myDetectorData.end(), data);
     278              :     if (it != myDetectorData.end()) {
     279              :         myDetectorData.erase(it);
     280              :     }
     281              :     for (const Queue& q : myQueues) {
     282              :         for (MEVehicle* const v : q.getVehicles()) {
     283              :             v->removeReminder(data);
     284              :         }
     285              :     }
     286              : }
     287              : */
     288              : 
     289              : 
     290              : void
     291      6424230 : MESegment::prepareDetectorForWriting(MSMoveReminder& data, int queueIndex) {
     292      6424230 :     const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
     293      6424230 :     if (queueIndex == -1) {
     294     12873040 :         for (const Queue& q : myQueues) {
     295              :             SUMOTime earliestExitTime = currentTime;
     296      7749258 :             for (std::vector<MEVehicle*>::const_reverse_iterator i = q.getVehicles().rbegin(); i != q.getVehicles().rend(); ++i) {
     297      1299848 :                 const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
     298      1299848 :                 (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
     299      1299848 :                 earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
     300              :             }
     301              :         }
     302              :     } else {
     303              :         SUMOTime earliestExitTime = currentTime;
     304          612 :         for (std::vector<MEVehicle*>::const_reverse_iterator i = myQueues[queueIndex].getVehicles().rbegin(); i != myQueues[queueIndex].getVehicles().rend(); ++i) {
     305           12 :             const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
     306           12 :             (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
     307           12 :             earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
     308              :         }
     309              :     }
     310      6424230 : }
     311              : 
     312              : 
     313              : SUMOTime
     314    141798034 : MESegment::hasSpaceFor(const MEVehicle* const veh, const SUMOTime entryTime, int& qIdx, const bool init) const {
     315              :     SUMOTime earliestEntry = SUMOTime_MAX;
     316    141798034 :     qIdx = 0;
     317    141798034 :     if (myNumVehicles == 0 && myQueues.size() == 1) {
     318              :         // we have always space for at least one vehicle
     319     27668666 :         if (myQueues.front().allows(veh->getVClass())) {
     320              :             return entryTime;
     321              :         }  else {
     322              :             return earliestEntry;
     323              :         }
     324              :     }
     325    114129368 :     const SUMOVehicleClass svc = veh->getVClass();
     326              :     int minSize = std::numeric_limits<int>::max();
     327    114839909 :     const MSEdge* const succ = myNextSegment == nullptr ? veh->succEdge(veh->getEdge() == &myEdge ? 1 : 2) : nullptr;
     328    300907373 :     for (int i = 0; i < (int)myQueues.size(); i++) {
     329    186778005 :         const Queue& q = myQueues[i];
     330    186778005 :         const double newOccupancy = q.size() == 0 ? 0. : q.getOccupancy() + veh->getVehicleType().getLengthWithGap();
     331    186778005 :         if (newOccupancy <= myQueueCapacity) { // we must ensure that occupancy remains below capacity
     332     60546231 :             if (succ == nullptr || myFollowerMap.count(succ) == 0 || ((myFollowerMap.find(succ)->second & (1 << i)) != 0)) {
     333     41748349 :                 if (q.allows(svc) && q.size() < minSize) {
     334     26536870 :                     if (init) {
     335              :                         // regular insertions and initial insertions must respect different constraints:
     336      8208785 :                         if (veh->getInsertionChecks() == (int)InsertionCheck::NONE || hasSpaceForInsertion(q, i, newOccupancy, entryTime)) {
     337      4974412 :                             qIdx = i;
     338              :                             minSize = q.size();
     339              :                         }
     340     18328085 :                     } else if (entryTime >= q.getEntryBlockTime()) {
     341     18059895 :                         qIdx = i;
     342              :                         minSize = q.size();
     343              :                     } else {
     344              :                         earliestEntry = MIN2(earliestEntry, q.getEntryBlockTime());
     345              :                     }
     346              :                 }
     347              :             }
     348              :         }
     349              :     }
     350    114129368 :     if (minSize == std::numeric_limits<int>::max()) {
     351              :         return earliestEntry;
     352              :     }
     353              :     return entryTime;
     354              : }
     355              : 
     356              : 
     357              : bool
     358      8208741 : MESegment::hasSpaceForInsertion(const Queue& q, int /*qIdx*/, double newOccupancy, SUMOTime /*entryTime*/) const {
     359              :     // - regular insertions must respect entryBlockTime
     360              :     // - initial insertions should not cause additional jamming
     361              :     // - inserted vehicle should be able to continue at the current speed
     362      8208741 :     if (q.getOccupancy() <= myJamThreshold && !hasBlockedLeader() && !myTLSPenalty) {
     363      3982122 :         return newOccupancy <= myJamThreshold;
     364              :     } else {
     365      4226619 :         return newOccupancy <= jamThresholdForSpeed(getMeanSpeed(false), -1);
     366              :     }
     367              : }
     368              : 
     369              : 
     370              : bool
     371     11090777 : MESegment::initialise(MEVehicle* veh, SUMOTime time) {
     372     11090777 :     int qIdx = 0;
     373     11090777 :     if (hasSpaceFor(veh, time, qIdx, true) == time) {
     374      9177598 :         const bool isRail = veh->isRail();
     375              :         // see MSLane::isInsertionSuccess
     376      8348207 :         if (isRail && veh->getInsertionChecks() != (int)InsertionCheck::NONE
     377      8348188 :                 && veh->getParameter().departProcedure != DepartDefinition::SPLIT
     378      8348188 :                 && MSRailSignalControl::isSignalized(veh->getVClass())
     379     17525777 :                 && isRailwayOrShared(myEdge.getPermissions())) {
     380      8348173 :             const MSDriveWay* dw = MSDriveWay::getDepartureDriveway(veh);
     381              :             MSEdgeVector occupied;
     382      8348173 :             if (dw->foeDriveWayOccupied(false, veh, occupied)) {
     383      8345975 :                 myEdge.getLanes()[0]->setParameter("insertionBlocked:" + veh->getID(), dw->getID());
     384              :                 return false;
     385              :             }
     386      8348173 :         }
     387       831623 :         receive(veh, qIdx, time, true);
     388       831623 :         if (isRail) {
     389         4464 :             myEdge.getLanes()[0]->unsetParameter("insertionConstraint:" + veh->getID());
     390              :             //unsetParameter("insertionOrder:" + veh->getID());
     391              :             //unsetParameter("insertionBlocked:" + veh->getID());
     392              :             //// rail_signal (not traffic_light) requires approach information for
     393              :             //// switching correctly at the start of the next simulation step
     394              :             //if (firstRailSignal != nullptr && firstRailSignal->getJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
     395              :             //    veh->registerInsertionApproach(firstRailSignal, firstRailSignalDist);
     396              :             //}
     397              :         }
     398              :         // we can check only after insertion because insertion may change the route via devices
     399              :         std::string msg;
     400      1662498 :         if (MSGlobals::gCheckRoutes && !veh->hasValidRoute(msg)) {
     401            6 :             throw ProcessError(TLF("Vehicle '%' has no valid route. %", veh->getID(), msg));
     402              :         }
     403              :         return true;
     404              :     }
     405              :     return false;
     406              : }
     407              : 
     408              : 
     409              : double
     410     29689648 : MESegment::getMeanSpeed(bool useCached) const {
     411     29689648 :     const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
     412     29689648 :     if (currentTime != myLastMeanSpeedUpdate || !useCached) {
     413     29587310 :         myLastMeanSpeedUpdate = currentTime;
     414              :         double v = 0;
     415              :         int count = 0;
     416     61339349 :         for (const Queue& q : myQueues) {
     417     31752039 :             const SUMOTime tau = q.getOccupancy() < myJamThreshold ? myTau_ff : myTau_jf;
     418     31752039 :             SUMOTime earliestExitTime = currentTime;
     419     31752039 :             count += q.size();
     420    186424901 :             for (std::vector<MEVehicle*>::const_reverse_iterator veh = q.getVehicles().rbegin(); veh != q.getVehicles().rend(); ++veh) {
     421    154672862 :                 v += (*veh)->getConservativeSpeed(earliestExitTime); // earliestExitTime is updated!
     422    154672862 :                 earliestExitTime += tauWithVehLength(tau, (*veh)->getVehicleType().getLengthWithGap(), (*veh)->getVehicleType().getCarFollowModel().getHeadwayTime());
     423              :             }
     424              :         }
     425     29587310 :         if (count == 0) {
     426           30 :             myMeanSpeed = myEdge.getSpeedLimit();
     427              :         } else {
     428     29587280 :             myMeanSpeed = v / (double) count;
     429              :         }
     430              :     }
     431     29689648 :     return myMeanSpeed;
     432              : }
     433              : 
     434              : 
     435              : void
     436         5226 : MESegment::resetCachedSpeeds() {
     437         5226 :     myLastMeanSpeedUpdate = SUMOTime_MIN;
     438         5226 : }
     439              : 
     440              : void
     441        11953 : MESegment::writeVehicles(OutputDevice& of) const {
     442        24082 :     for (const Queue& q : myQueues) {
     443        14162 :         for (const MEVehicle* const veh : q.getVehicles()) {
     444         2033 :             MSXMLRawOut::writeVehicle(of, *veh);
     445              :         }
     446              :     }
     447        11953 : }
     448              : 
     449              : 
     450              : MEVehicle*
     451     26678510 : MESegment::removeCar(MEVehicle* v, SUMOTime leaveTime, const MSMoveReminder::Notification reason) {
     452     26678510 :     Queue& q = myQueues[v->getQueIndex()];
     453              :     // One could be tempted to do  v->setSegment(next); here but position on lane will be invalid if next == 0
     454     26678510 :     v->updateDetectors(leaveTime, v->getEventTime(), true, reason);
     455     26678510 :     myNumVehicles--;
     456     26678510 :     myEdge.lock();
     457     26678510 :     MEVehicle* nextLeader = q.remove(v);
     458     26678510 :     myEdge.invalidateMesoCache();
     459     26678510 :     myEdge.unlock();
     460     26678510 :     return nextLeader;
     461              : }
     462              : 
     463              : 
     464              : SUMOTime
     465        13655 : MESegment::getNextInsertionTime(SUMOTime earliestEntry) const {
     466              :     // since we do not know which queue will be used we give a conservative estimate
     467              :     SUMOTime earliestLeave = earliestEntry;
     468              :     SUMOTime latestEntry = -1;
     469        27575 :     for (const Queue& q : myQueues) {
     470              :         earliestLeave = MAX2(earliestLeave, q.getBlockTime());
     471              :         latestEntry = MAX2(latestEntry, q.getEntryBlockTime());
     472              :     }
     473        13655 :     if (myEdge.getSpeedLimit() == 0) {
     474           12 :         return MAX2(earliestEntry, latestEntry);    // FIXME: This line is just an adhoc-fix to avoid division by zero (Leo)
     475              :     } else {
     476        13643 :         return MAX3(earliestEntry, earliestLeave - TIME2STEPS(myLength / myEdge.getSpeedLimit()), latestEntry);
     477              :     }
     478              : }
     479              : 
     480              : 
     481              : MSLink*
     482    127359115 : MESegment::getLink(const MEVehicle* veh, bool penalty) const {
     483    127359115 :     if (myJunctionControl || penalty) {
     484     29815382 :         const MSEdge* const nextEdge = veh->succEdge(1);
     485     29815382 :         if (nextEdge == nullptr || veh->getQueIndex() == PARKING_QUEUE) {
     486              :             return nullptr;
     487              :         }
     488              :         // try to find any link leading to our next edge, start with the lane pointed to by the que index
     489     28494260 :         const MSLane* const bestLane = myEdge.getLanes()[veh->getQueIndex()];
     490     32786366 :         for (MSLink* const link : bestLane->getLinkCont()) {
     491     32373383 :             if (&link->getLane()->getEdge() == nextEdge) {
     492              :                 return link;
     493              :             }
     494              :         }
     495              :         // this is for the non-multique case, maybe we should use caching here !!!
     496       937268 :         for (const MSLane* const lane : myEdge.getLanes()) {
     497       920613 :             if (lane != bestLane) {
     498       640140 :                 for (MSLink* const link : lane->getLinkCont()) {
     499       527074 :                     if (&link->getLane()->getEdge() == nextEdge) {
     500              :                         return link;
     501              :                     }
     502              :                 }
     503              :             }
     504              :         }
     505              :     }
     506              :     return nullptr;
     507              : }
     508              : 
     509              : 
     510              : bool
     511     35175592 : MESegment::isOpen(const MEVehicle* veh) const {
     512              : #ifdef DEBUG_OPENED
     513              :     if (DEBUG_COND || DEBUG_COND2(veh)) {
     514              :         gDebugFlag1 = true;
     515              :         std::cout << SIMTIME << " opened seg=" << getID() << " veh=" << Named::getIDSecure(veh)
     516              :                   << " tlsPenalty=" << myTLSPenalty;
     517              :         const MSLink* link = getLink(veh);
     518              :         if (link == 0) {
     519              :             std::cout << " link=0";
     520              :         } else {
     521              :             std::cout << " prio=" << link->havePriority()
     522              :                       << " override=" << limitedControlOverride(link)
     523              :                       << " isOpen=" << link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
     524              :                                                     veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
     525              :                                                     veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime(),
     526              :                                                     0, nullptr, false, veh)
     527              :                       << " et=" << veh->getEventTime()
     528              :                       << " v=" << veh->getSpeed()
     529              :                       << " vLeave=" << veh->estimateLeaveSpeed(link)
     530              :                       << " impatience=" << veh->getImpatience()
     531              :                       << " tWait=" << veh->getWaitingTime();
     532              :         }
     533              :         std::cout << "\n";
     534              :         gDebugFlag1 = false;
     535              :     }
     536              : #endif
     537     35175592 :     if (myTLSPenalty) {
     538              :         // XXX should limited control take precedence over tls penalty?
     539              :         return true;
     540              :     }
     541     35123444 :     const MSLink* link = getLink(veh);
     542              :     return (link == nullptr
     543     11331258 :             || link->havePriority()
     544      9592541 :             || limitedControlOverride(link)
     545     44715221 :             || link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
     546      9591777 :                             veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
     547      9591777 :                             veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime(),
     548              :                             0, nullptr, false, veh));
     549              : }
     550              : 
     551              : 
     552              : bool
     553      9595731 : MESegment::limitedControlOverride(const MSLink* link) const {
     554              :     assert(link != nullptr);
     555      9595731 :     if (!MSGlobals::gMesoLimitedJunctionControl) {
     556              :         return false;
     557              :     }
     558              :     // if the target segment of this link is not saturated junction control is disabled
     559              :     const MSEdge& targetEdge = link->getLane()->getEdge();
     560         8400 :     const MESegment* target = MSGlobals::gMesoNet->getSegmentForEdge(targetEdge);
     561         8400 :     return (target->getBruttoOccupancy() * 2 < target->myJamThreshold) && !targetEdge.isRoundabout();
     562              : }
     563              : 
     564              : 
     565              : SUMOTime
     566     25885152 : MESegment::computeHeadway(Queue& /*q*/, const Queue& qNext, const MESegment* const next, const MEVehicle* veh) const {
     567     25885152 :     const bool nextFree = qNext.getOccupancy() <= next->myJamThreshold;
     568              :     const SUMOTime tau = (!veh->wasJammed()
     569     25885152 :             ? (nextFree ? myTau_ff : myTau_fj)
     570       726695 :             : (nextFree ? myTau_jf : getTauJJ((double)qNext.size(), next->myQueueCapacity, next->myJamThreshold)));
     571              :     assert(tau >= 0);
     572     25885152 :     SUMOTime headway = tauWithVehLength(tau, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime());
     573     25885152 :     if (myTLSPenalty) {
     574        52148 :         const MSLink* const tllink = getLink(veh, true);
     575        52148 :         if (tllink != nullptr && tllink->isTLSControlled()) {
     576              :             assert(tllink->getGreenFraction() > 0);
     577        49540 :             headway = (SUMOTime)((double)headway / tllink->getGreenFraction());
     578              :         }
     579              :     }
     580     25885152 :     return headway;
     581              : }
     582              : 
     583              : 
     584              : void
     585     26678510 : MESegment::send(MEVehicle* veh, MESegment* const next, const int nextQIdx, SUMOTime time, const MSMoveReminder::Notification reason) {
     586     26678510 :     Queue& q = myQueues[veh->getQueIndex()];
     587              :     assert(isInvalid(next) || time >= q.getBlockTime());
     588     26678510 :     MSLink* const link = getLink(veh);
     589     26678510 :     if (link != nullptr) {
     590      2051487 :         link->removeApproaching(veh);
     591              :     }
     592     26678510 :     if (veh->isStopped()) {
     593         8464 :         veh->processStop();
     594              :     }
     595     26678510 :     MEVehicle* lc = removeCar(veh, time, reason); // new leaderCar
     596              :     q.setBlockTime(time);
     597     26678510 :     if (myEdge.isNormal() && myCapacity >= 22.5 ) {
     598     20395610 :         veh->markJammed(q.getOccupancy() > myJamThreshold);
     599              :     }
     600              :     if (!isInvalid(next)) {
     601     25885152 :         myLastHeadway = computeHeadway(q, next->myQueues[nextQIdx], next, veh);
     602     25885152 :         q.setBlockTime(time + myLastHeadway);
     603              :     }
     604     26678510 :     if (lc != nullptr) {
     605              :         lc->setEventTime(MAX2(lc->getEventTime(), q.getBlockTime()));
     606     18225410 :         MSGlobals::gMesoNet->addLeaderCar(lc, getLink(lc));
     607              :     }
     608     26678510 : }
     609              : 
     610              : 
     611              : SUMOTime
     612       191353 : MESegment::getTauJJ(double nextQueueSize, double nextQueueCapacity, double nextJamThreshold) const {
     613              :     // compute coefficients for the jam-jam headway function
     614              :     // this function models the effect that "empty space" needs to move
     615              :     // backwards through the downstream segment before the upstream segment may
     616              :     // send annother vehicle.
     617              :     // this allows jams to clear and move upstream.
     618              :     // the headway function f(x) depends on the number of vehicles in the
     619              :     // downstream segment x
     620              :     // f is a linear function that passes through the following fixed points:
     621              :     // f(n_jam_threshold) = tau_jf_withLength (for continuity)
     622              :     // f(headwayCapacity) = myTau_jj * headwayCapacity
     623              : 
     624       191353 :     const SUMOTime tau_jf_withLength = tauWithVehLength(myTau_jf, DEFAULT_VEH_LENGTH_WITH_GAP, 1.);
     625              :     // number of vehicles that fit into the NEXT queue (could be larger than expected with DEFAULT_VEH_LENGTH_WITH_GAP!)
     626       191353 :     const double headwayCapacity = MAX2(nextQueueSize, nextQueueCapacity / DEFAULT_VEH_LENGTH_WITH_GAP);
     627              :     // number of vehicles above which the NEXT queue is jammed
     628       191353 :     const double n_jam_threshold = headwayCapacity * nextJamThreshold / nextQueueCapacity;
     629              : 
     630              :     // slope a and axis offset b for the jam-jam headway function
     631              :     // solving f(x) = a * x + b
     632       191353 :     const double a = (STEPS2TIME(myTau_jj) * headwayCapacity - STEPS2TIME(tau_jf_withLength)) / (headwayCapacity - n_jam_threshold);
     633       191353 :     const double b = headwayCapacity * (STEPS2TIME(myTau_jj) - a);
     634              : 
     635              :     // it is only well defined for nextQueueSize >= n_jam_threshold (which may not be the case for longer vehicles), so we take the MAX
     636       191353 :     return TIME2STEPS(a * MAX2(nextQueueSize, n_jam_threshold) + b);
     637              : }
     638              : 
     639              : 
     640              : bool
     641      1206806 : MESegment::overtake() {
     642      1206830 :     return myOvertaking && RandHelper::rand() > (getBruttoOccupancy() / myCapacity);
     643              : }
     644              : 
     645              : 
     646              : void
     647     26725962 : MESegment::addReminders(MEVehicle* veh) const {
     648     26725962 :     if (veh->getQueIndex() != PARKING_QUEUE) {
     649     26720154 :         myQueues[veh->getQueIndex()].addReminders(veh);
     650              :     }
     651     26725962 : }
     652              : 
     653              : 
     654              : void
     655     26722978 : MESegment::receive(MEVehicle* veh, const int qIdx, SUMOTime time, const bool isDepart, const bool isTeleport, const bool newEdge) {
     656     26722978 :     const double speed = isDepart ? -1 : MAX2(veh->getSpeed(), MESO_MIN_SPEED); // on the previous segment
     657     26722978 :     veh->setSegment(this); // for arrival checking
     658              :     veh->setLastEntryTime(time);
     659              :     veh->setBlockTime(SUMOTime_MAX);
     660     26722978 :     if (!isDepart && (
     661              :                 // arrival on entering a new edge
     662      5043389 :                 (newEdge && myEdge.isNormal() && veh->moveRoutePointer())
     663              :                 // arrival on entering a new segment
     664     25891196 :                 || veh->hasArrived())) {
     665              :         // route has ended
     666        15352 :         veh->setEventTime(time + TIME2STEPS(myLength / speed)); // for correct arrival speed
     667        15352 :         addReminders(veh);
     668        15352 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
     669        30600 :         veh->updateDetectors(time, veh->getEventTime(), true,
     670        15352 :                              veh->getEdge()->isVaporizing() ? MSMoveReminder::NOTIFICATION_VAPORIZED_VAPORIZER : MSMoveReminder::NOTIFICATION_ARRIVED);
     671        15352 :         MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
     672        15352 :         return;
     673              :     }
     674              :     assert(veh->getEdge() == &getEdge() || getEdge().isInternal());
     675              :     // route continues
     676     26707626 :     Queue& q = myQueues[qIdx];
     677     26707626 :     const double maxSpeedOnEdge = veh->getEdge()->getLanes()[qIdx]->getVehicleMaxSpeed(veh);
     678              :     const double uspeed = MAX2(maxSpeedOnEdge, MESO_MIN_SPEED);
     679              :     std::vector<MEVehicle*>& cars = q.getModifiableVehicles();
     680              :     MEVehicle* newLeader = nullptr; // first vehicle in the current queue
     681     26707626 :     const SUMOTime stopTime = veh->checkStop(time);
     682     26707626 :     SUMOTime tleave = MAX2(stopTime + TIME2STEPS(myLength / uspeed) + getLinkPenalty(veh), q.getBlockTime());
     683     26707626 :     if (veh->isStopped()) {
     684        14917 :         myEdge.addWaiting(veh);
     685              :     }
     686     26707626 :     if (veh->isParking()) {
     687              :         // parking stops should take at least 1ms
     688         5808 :         veh->setEventTime(MAX2(stopTime, veh->getEventTime() + 1));
     689         5808 :         veh->setSegment(this, PARKING_QUEUE);
     690         5808 :         myEdge.getLanes()[0]->addParking(veh);  // TODO for GUI only
     691              :     } else {
     692     26701818 :         myEdge.lock();
     693     26701818 :         if (cars.empty()) {
     694      8453571 :             cars.push_back(veh);
     695              :             newLeader = veh;
     696              :         } else {
     697     18248247 :             SUMOTime leaderOut = cars[0]->getEventTime();
     698     18248247 :             if (!isDepart && leaderOut > tleave && overtake()) {
     699           20 :                 if (cars.size() == 1) {
     700            4 :                     MSGlobals::gMesoNet->removeLeaderCar(cars[0]);
     701              :                     newLeader = veh;
     702              :                 }
     703           20 :                 cars.insert(cars.begin() + 1, veh);
     704              :             } else {
     705     18248227 :                 tleave = MAX2(leaderOut + tauWithVehLength(myTau_ff, cars[0]->getVehicleType().getLengthWithGap(), cars[0]->getVehicleType().getCarFollowModel().getHeadwayTime()), tleave);
     706     18248227 :                 cars.insert(cars.begin(), veh);
     707              :             }
     708              :         }
     709     26701818 :         myEdge.invalidateMesoCache();
     710     26701818 :         myEdge.unlock();
     711     26701818 :         myNumVehicles++;
     712     26701818 :         if (!isDepart && !isTeleport) {
     713              :             // departs and teleports could take place anywhere on the edge so they should not block regular flow
     714              :             // the -1 facilitates interleaving of multiple streams
     715     25869720 :             q.setEntryBlockTime(time + tauWithVehLength(myTau_ff, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime()) - 1);
     716              :         }
     717     26701818 :         q.setOccupancy(MIN2(myQueueCapacity, q.getOccupancy() + veh->getVehicleType().getLengthWithGap()));
     718              :         veh->setEventTime(tleave);
     719              :         veh->setUnqueuedEventTime(tleave);
     720     26701818 :         veh->setSegment(this, qIdx);
     721              :     }
     722     26707626 :     addReminders(veh);
     723     26707626 :     if (isDepart) {
     724       831623 :         veh->onDepart();
     725       831623 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_DEPARTED);
     726     25876003 :     } else if (newEdge) {
     727      5043230 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
     728              :     } else {
     729     20832773 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_SEGMENT);
     730              :     }
     731     26707626 :     if (veh->isParking()) {
     732         5828 :         MSGlobals::gMesoNet->addLeaderCar(veh, nullptr);
     733              :     } else {
     734     26701798 :         if (newLeader != nullptr) {
     735      8453557 :             MSGlobals::gMesoNet->addLeaderCar(newLeader, getLink(newLeader));
     736              :         }
     737              :     }
     738              : }
     739              : 
     740              : 
     741              : bool
     742         8752 : MESegment::vaporizeAnyCar(SUMOTime currentTime, const MSDetectorFileOutput* filter) {
     743         9304 :     for (const Queue& q : myQueues) {
     744         8778 :         if (q.size() > 0) {
     745         8226 :             for (MEVehicle* const veh : q.getVehicles()) {
     746         8226 :                 if (filter->vehicleApplies(*veh)) {
     747         8226 :                     MSGlobals::gMesoNet->removeLeaderCar(veh);
     748         8226 :                     MSGlobals::gMesoNet->changeSegment(veh, currentTime + 1, &myVaporizationTarget, MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR);
     749              :                     return true;
     750              :                 }
     751              :             }
     752              :         }
     753              :     }
     754              :     return false;
     755              : }
     756              : 
     757              : 
     758              : void
     759          352 : MESegment::setSpeedForQueue(double newSpeed, SUMOTime currentTime, SUMOTime blockTime, const std::vector<MEVehicle*>& vehs) {
     760          352 :     MEVehicle* v = vehs.back();
     761              :     SUMOTime oldEarliestExitTime = currentTime;
     762              :     const SUMOTime oldExit = MAX2(oldEarliestExitTime, v->getEventTime());
     763          352 :     v->updateDetectors(currentTime, oldExit, false);
     764          352 :     oldEarliestExitTime = oldExit + tauWithVehLength(myTau_ff, v->getVehicleType().getLengthWithGap(), v->getVehicleType().getCarFollowModel().getHeadwayTime());
     765          352 :     SUMOTime newEvent = MAX2(newArrival(v, newSpeed, currentTime), blockTime);
     766          352 :     if (v->getEventTime() != newEvent) {
     767          330 :         MSGlobals::gMesoNet->removeLeaderCar(v);
     768              :         v->setEventTime(newEvent);
     769          330 :         MSGlobals::gMesoNet->addLeaderCar(v, getLink(v));
     770              :     }
     771         1075 :     for (std::vector<MEVehicle*>::const_reverse_iterator i = vehs.rbegin() + 1; i != vehs.rend(); ++i) {
     772          723 :         const SUMOTime oldExitTime = MAX2(oldEarliestExitTime, (*i)->getEventTime());
     773          723 :         (*i)->updateDetectors(currentTime, oldExitTime, false);
     774          723 :         const SUMOTime minTau = tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
     775          723 :         oldEarliestExitTime = oldExitTime + minTau;
     776          723 :         newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + minTau);
     777          723 :         (*i)->setEventTime(newEvent);
     778              :     }
     779          352 : }
     780              : 
     781              : 
     782              : SUMOTime
     783         1075 : MESegment::newArrival(const MEVehicle* const v, double newSpeed, SUMOTime currentTime) {
     784              :     // since speed is only an upper bound, pos may be too optimistic
     785         1075 :     const double pos = MIN2(myLength, STEPS2TIME(currentTime - v->getLastEntryTime()) * v->getSpeed());
     786              :     // traveltime may not be 0
     787         1075 :     double tt = (myLength - pos) / MAX2(newSpeed, MESO_MIN_SPEED);
     788         1075 :     return currentTime + MAX2(TIME2STEPS(tt), SUMOTime(1));
     789              : }
     790              : 
     791              : 
     792              : void
     793         1044 : MESegment::setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh, int qIdx) {
     794         1044 :     recomputeJamThreshold(jamThresh);
     795              :     //myTau_length = MAX2(MESO_MIN_SPEED, newSpeed) * myEdge.getLanes().size() / TIME2STEPS(1);
     796              :     int i = 0;
     797         2182 :     for (const Queue& q : myQueues) {
     798         1138 :         if (q.size() != 0) {
     799          386 :             if (qIdx == -1 || qIdx == i) {
     800          352 :                 setSpeedForQueue(newSpeed, currentTime, q.getBlockTime(), q.getVehicles());
     801              :             }
     802              :         }
     803         1138 :         i++;
     804              :     }
     805         1044 : }
     806              : 
     807              : 
     808              : SUMOTime
     809      2081142 : MESegment::getEventTime() const {
     810              :     SUMOTime result = SUMOTime_MAX;
     811      4429759 :     for (const Queue& q : myQueues) {
     812      2348617 :         if (q.size() != 0 && q.getVehicles().back()->getEventTime() < result) {
     813              :             result = q.getVehicles().back()->getEventTime();
     814              :         }
     815              :     }
     816      2081142 :     if (result < SUMOTime_MAX) {
     817       969153 :         return result;
     818              :     }
     819              :     return -1;
     820              : }
     821              : 
     822              : 
     823              : void
     824        11928 : MESegment::saveState(OutputDevice& out) const {
     825              :     bool write = false;
     826        23063 :     for (const Queue& q : myQueues) {
     827        12407 :         if (q.getBlockTime() != -1 || !q.getVehicles().empty()) {
     828              :             write = true;
     829              :             break;
     830              :         }
     831              :     }
     832        11928 :     if (write) {
     833         1272 :         out.openTag(SUMO_TAG_SEGMENT).writeAttr(SUMO_ATTR_ID, getID());
     834         2602 :         for (const Queue& q : myQueues) {
     835         1330 :             out.openTag(SUMO_TAG_VIEWSETTINGS_VEHICLES);
     836         1330 :             out.writeAttr(SUMO_ATTR_TIME, toString<SUMOTime>(q.getBlockTime()));
     837         1330 :             out.writeAttr(SUMO_ATTR_BLOCKTIME, toString<SUMOTime>(q.getEntryBlockTime()));
     838         1330 :             out.writeAttr(SUMO_ATTR_VALUE, q.getVehicles());
     839         2660 :             out.closeTag();
     840              :         }
     841         2544 :         out.closeTag();
     842              :     }
     843        11928 : }
     844              : 
     845              : 
     846              : void
     847          398 : MESegment::clearState() {
     848          836 :     for (Queue& q : myQueues) {
     849              :         q.getModifiableVehicles().clear();
     850              :     }
     851          398 : }
     852              : 
     853              : void
     854         1161 : MESegment::loadState(const std::vector<SUMOVehicle*>& vehs, const SUMOTime blockTime, const SUMOTime entryBlockTime, const int queIdx) {
     855         1161 :     Queue& q = myQueues[queIdx];
     856         1655 :     for (SUMOVehicle* veh : vehs) {
     857          494 :         MEVehicle* v = static_cast<MEVehicle*>(veh);
     858              :         assert(v->getSegment() == this || myEdge.isInternal());
     859          494 :         if (myEdge.isInternal()) {
     860           13 :             v->setSegment(this, v->getQueIndex());
     861              :         }
     862          494 :         q.getModifiableVehicles().push_back(v);
     863          494 :         myNumVehicles++;
     864          494 :         q.setOccupancy(q.getOccupancy() + v->getVehicleType().getLengthWithGap());
     865          494 :         addReminders(v);
     866              :     }
     867         1161 :     if (q.size() != 0) {
     868              :         // add the last vehicle of this queue
     869              :         // !!! one question - what about the previously added vehicle? Is it stored twice?
     870          255 :         MEVehicle* veh = q.getVehicles().back();
     871          255 :         MSGlobals::gMesoNet->addLeaderCar(veh, getLink(veh));
     872              :     }
     873              :     q.setBlockTime(blockTime);
     874              :     q.setEntryBlockTime(entryBlockTime);
     875         1161 :     q.setOccupancy(MIN2(q.getOccupancy(), myQueueCapacity));
     876         1161 : }
     877              : 
     878              : 
     879              : std::vector<const MEVehicle*>
     880          122 : MESegment::getVehicles() const {
     881              :     std::vector<const MEVehicle*> result;
     882          316 :     for (const Queue& q : myQueues) {
     883          194 :         result.insert(result.end(), q.getVehicles().begin(), q.getVehicles().end());
     884              :     }
     885          122 :     return result;
     886            0 : }
     887              : 
     888              : 
     889              : bool
     890      4014415 : MESegment::hasBlockedLeader() const {
     891      8081126 :     for (const Queue& q : myQueues) {
     892      4098730 :         if (q.size() > 0 && q.getVehicles().back()->getWaitingTime() > 0) {
     893              :             return true;
     894              :         }
     895              :     }
     896              :     return false;
     897              : }
     898              : 
     899              : 
     900              : double
     901            0 : MESegment::getFlow() const {
     902            0 :     return 3600 * getCarNumber() * getMeanSpeed() / myLength;
     903              : }
     904              : 
     905              : 
     906              : SUMOTime
     907     26707626 : MESegment::getLinkPenalty(const MEVehicle* veh) const {
     908     26707626 :     const MSLink* link = getLink(veh, myTLSPenalty || myCheckMinorPenalty);
     909     26707626 :     if (link != nullptr) {
     910              :         SUMOTime result = 0;
     911      2106251 :         if (link->isTLSControlled() && myTLSPenalty) {
     912              :             result += link->getMesoTLSPenalty();
     913              :         }
     914              :         // minor tls links may get an additional penalty
     915       414409 :         if (!link->havePriority() &&
     916              :                 // do not apply penalty on top of tLSPenalty
     917      2106251 :                 !myTLSPenalty &&
     918              :                 // do not apply penalty if limited control is active
     919       378527 :                 (!MSGlobals::gMesoLimitedJunctionControl || limitedControlOverride(link))) {
     920       376057 :             result += myMinorPenalty;
     921              :         }
     922      2106251 :         return result;
     923              :     } else {
     924              :         return 0;
     925              :     }
     926              : }
     927              : 
     928              : 
     929              : double
     930            9 : MESegment::getWaitingSeconds() const {
     931              :     double result = 0;
     932           22 :     for (const Queue& q : myQueues) {
     933              :         // @note: only the leader currently accumulates waitingTime but this might change in the future
     934           16 :         for (const MEVehicle* veh : q.getVehicles()) {
     935            3 :             result += veh->getWaitingSeconds();
     936              :         }
     937              :     }
     938            9 :     return result;
     939              : }
     940              : 
     941              : 
     942              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1