LCOV - code coverage report
Current view: top level - src/mesosim - MESegment.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 99.3 % 406 403
Test Date: 2026-09-20 15:45:03 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              : SVCPermissions MESegment::myMultiModalWarnings(0);
      65              : const double MESegment::DO_NOT_PATCH_JAM_THRESHOLD(std::numeric_limits<double>::max());
      66              : const std::string MESegment::OVERRIDE_TLS_PENALTIES("meso.tls.control");
      67              : 
      68              : 
      69              : // ===========================================================================
      70              : // MESegment::Queue method definitions
      71              : // ===========================================================================
      72              : MEVehicle*
      73     26735627 : MESegment::Queue::remove(MEVehicle* v) {
      74     26735627 :     myOccupancy -= v->getVehicleType().getLengthWithGap();
      75              :     assert(std::find(myVehicles.begin(), myVehicles.end(), v) != myVehicles.end());
      76     26735627 :     if (v == myVehicles.back()) {
      77              :         myVehicles.pop_back();
      78     26729348 :         if (myVehicles.empty()) {
      79      8453687 :             myOccupancy = 0.;
      80              :         } else {
      81     18275661 :             return myVehicles.back();
      82              :         }
      83              :     } else {
      84         6279 :         myVehicles.erase(std::find(myVehicles.begin(), myVehicles.end(), v));
      85              :     }
      86              :     return nullptr;
      87              : }
      88              : 
      89              : void
      90       132284 : MESegment::Queue::addDetector(MSMoveReminder* data) {
      91       132284 :     myDetectorData.push_back(data);
      92       138034 :     for (MEVehicle* const v : myVehicles) {
      93         5750 :         v->addReminder(data);
      94              :     }
      95       132284 : }
      96              : 
      97              : void
      98     26777564 : MESegment::Queue::addReminders(MEVehicle* veh) const {
      99     36453928 :     for (MSMoveReminder* rem : myDetectorData) {
     100      9676364 :         veh->addReminder(rem);
     101              :     }
     102     26777564 : }
     103              : 
     104              : // ===========================================================================
     105              : // MESegment method definitions
     106              : // ===========================================================================
     107       727505 : MESegment::MESegment(const std::string& id,
     108              :                      const MSEdge& parent, MESegment* next,
     109              :                      const double length, const double speed,
     110              :                      const int idx,
     111              :                      const bool multiQueue,
     112       727505 :                      const MesoEdgeType& edgeType):
     113       727505 :     Named(id), myEdge(parent), myNextSegment(next),
     114       727505 :     myLength(length), myIndex(idx),
     115       727505 :     myTau_length(TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, speed)),
     116       727505 :     myNumVehicles(0),
     117       727505 :     myLastHeadway(TIME2STEPS(-1)),
     118       727505 :     myMeanSpeed(speed),
     119      1454683 :     myLastMeanSpeedUpdate(SUMOTime_MIN) {
     120              : 
     121              :     const std::vector<MSLane*>& lanes = parent.getLanes();
     122              :     int usableLanes = 0;
     123              :     SVCPermissions maxAllow = 0;
     124       727505 :     SVCPermissions minAllow = SVCAll;
     125      1580663 :     for (MSLane* const l : lanes) {
     126       853158 :         const SVCPermissions allow = MSEdge::getMesoPermissions(l->getPermissions());
     127       853158 :         if (multiQueue) {
     128       111424 :             myQueues.push_back(Queue(allow));
     129              :         }
     130       853158 :         if (allow != 0) {
     131       799637 :             usableLanes++;
     132       799637 :             maxAllow |= allow;
     133       799637 :             minAllow &= allow;
     134              :         }
     135              :     }
     136       727505 :     if (usableLanes == 0) {
     137              :         // cars won't drive here. Give sensible tau values capacity for the ignored classes
     138              :         usableLanes = 1;
     139              :     }
     140       727505 :     if (multiQueue) {
     141        23749 :         if (next == nullptr) {
     142       110289 :             for (const MSEdge* const edge : parent.getSuccessors()) {
     143        86893 :                 if (edge->isTazConnector()) {
     144          284 :                     continue;
     145              :                 }
     146        86609 :                 const std::vector<MSLane*>* const allowed = parent.allowedLanes(*edge);
     147              :                 assert(allowed != nullptr);
     148              :                 assert(allowed->size() > 0);
     149       181203 :                 for (MSLane* const l : *allowed) {
     150        94594 :                     std::vector<MSLane*>::const_iterator it = std::find(lanes.begin(), lanes.end(), l);
     151        94594 :                     myFollowerMap[edge] |= (1 << distance(lanes.begin(), it));
     152              :                 }
     153              :             }
     154              :         }
     155        23749 :         myQueueCapacity = length;
     156              :     } else {
     157       703756 :         myQueues.push_back(Queue(parent.getPermissions()));
     158       703756 :         maxAllow &= ~minAllow;
     159       703756 :         if ((maxAllow & ~myMultiModalWarnings) != 0) {
     160          164 :             WRITE_WARNINGF("Mismodelled capacity on edge '%'. Not all lanes are usable by vClass '%'. Use option --meso-lane-queue or add unused class to option --meso-ignore-lanes-by-vclass.",
     161              :                     myEdge.getID(), getVehicleClassNames(maxAllow & ~myMultiModalWarnings));
     162           41 :             myMultiModalWarnings |= maxAllow;
     163              :         }
     164              :     }
     165              : 
     166       727505 :     initSegment(edgeType, parent, length * usableLanes);
     167       727505 : }
     168              : 
     169              : void
     170       727505 : MESegment::initSegment(const MesoEdgeType& edgeType, const MSEdge& parent, const double capacity) {
     171              : 
     172       727505 :     myCapacity = capacity;
     173       727505 :     if (myQueues.size() == 1) {
     174       704230 :         const double laneScale = capacity / myLength;
     175       704230 :         myQueueCapacity = capacity;
     176       704230 :         myTau_length = TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, myMeanSpeed) / laneScale;
     177              :         // Eissfeldt p. 90 and 151 ff.
     178       704230 :         myTau_ff = (SUMOTime)((double)edgeType.tauff / laneScale);
     179       704230 :         myTau_fj = (SUMOTime)((double)edgeType.taufj / laneScale);
     180       704230 :         myTau_jf = (SUMOTime)((double)edgeType.taujf / laneScale);
     181       704230 :         myTau_jj = (SUMOTime)((double)edgeType.taujj / laneScale);
     182              :     } else {
     183        23275 :         myTau_ff = edgeType.tauff;
     184        23275 :         myTau_fj = edgeType.taufj;
     185        23275 :         myTau_jf = edgeType.taujf;
     186        23275 :         myTau_jj = edgeType.taujj;
     187              :     }
     188              : 
     189       727505 :     myJunctionControl = myNextSegment == nullptr && (edgeType.junctionControl || MELoop::isEnteringRoundabout(parent));
     190       726729 :     myTLSPenalty = ((edgeType.tlsPenalty > 0 || edgeType.tlsFlowPenalty > 0) &&
     191              :                     // only apply to the last segment of a tls-controlled edge
     192       727865 :                     myNextSegment == nullptr && (
     193          298 :                         parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT ||
     194          298 :                         parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION ||
     195              :                         parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED));
     196              : 
     197              :     // only apply to the last segment of an uncontrolled edge that has at least 1 minor link
     198      1455330 :     myCheckMinorPenalty = (edgeType.minorPenalty > 0 &&
     199          320 :                            myNextSegment == nullptr &&
     200              :                            parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT &&
     201              :                            parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION &&
     202       727683 :                            parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
     203          178 :                            parent.hasMinorLink());
     204       727505 :     myMinorPenalty = edgeType.minorPenalty;
     205       727505 :     myOvertaking = edgeType.overtaking && myCapacity > myLength;
     206              : 
     207              :     //std::cout << getID() << " myMinorPenalty=" << myMinorPenalty << " myTLSPenalty=" << myTLSPenalty << " myJunctionControl=" << myJunctionControl << " myOvertaking=" << myOvertaking << "\n";
     208              : 
     209       727505 :     recomputeJamThreshold(edgeType.jamThreshold);
     210       727505 : }
     211              : 
     212        45681 : MESegment::MESegment(const std::string& id):
     213              :     Named(id),
     214        45681 :     myEdge(myDummyParent), // arbitrary edge needed to supply the needed reference
     215        45681 :     myNextSegment(nullptr), myLength(0), myIndex(0),
     216        45681 :     myTau_ff(0), myTau_fj(0), myTau_jf(0), myTau_jj(0),
     217        45681 :     myTLSPenalty(false),
     218        45681 :     myCheckMinorPenalty(false),
     219        45681 :     myMinorPenalty(0),
     220        45681 :     myJunctionControl(false),
     221        45681 :     myOvertaking(false),
     222        45681 :     myTau_length(1) {
     223        45681 : }
     224              : 
     225              : 
     226              : void
     227         1845 : MESegment::updatePermissions() {
     228         1845 :     if (myQueues.size() > 1) {
     229           64 :         for (MSLane* lane : myEdge.getLanes()) {
     230           48 :             myQueues[lane->getIndex()].setPermissions(lane->getPermissions());
     231              :         }
     232              :     } else {
     233         1829 :         myQueues.back().setPermissions(myEdge.getPermissions());
     234              :     }
     235         1845 : }
     236              : 
     237              : 
     238              : void
     239       728549 : MESegment::recomputeJamThreshold(double jamThresh) {
     240       728549 :     if (jamThresh == DO_NOT_PATCH_JAM_THRESHOLD) {
     241              :         return;
     242              :     }
     243       728549 :     if (jamThresh < 0) {
     244              :         // compute based on speed
     245       728537 :         myJamThreshold = jamThresholdForSpeed(myEdge.getSpeedLimit(), jamThresh);
     246              :     } else {
     247              :         // compute based on specified percentage
     248           12 :         myJamThreshold = jamThresh * myCapacity;
     249              :     }
     250              : }
     251              : 
     252              : 
     253              : double
     254      4962440 : MESegment::jamThresholdForSpeed(double speed, double jamThresh) const {
     255              :     // vehicles driving freely at maximum speed should not jam
     256              :     // we compute how many vehicles could possible enter the segment until the first vehicle leaves
     257              :     // and multiply by the space these vehicles would occupy
     258              :     // the jamThresh parameter is scale the resulting value
     259      4962440 :     if (speed == 0) {
     260              :         return std::numeric_limits<double>::max();  // never jam. Irrelevant at speed 0 anyway
     261              :     }
     262              : #ifdef DEBUG_JAMTHRESHOLD
     263              :     if (true || DEBUG_COND) {
     264              :         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
     265              :                   << "\n";
     266              :     }
     267              : #endif
     268      4962221 :     return std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGTH_WITH_GAP, 1.)))) * DEFAULT_VEH_LENGTH_WITH_GAP;
     269              : }
     270              : 
     271              : 
     272              : void
     273       128898 : MESegment::addDetector(MSMoveReminder* data, int queueIndex) {
     274       128898 :     if (queueIndex == -1) {
     275       254588 :         for (Queue& q : myQueues) {
     276       128987 :             q.addDetector(data);
     277              :         }
     278              :     } else {
     279              :         assert(queueIndex < (int)myQueues.size());
     280         3297 :         myQueues[queueIndex].addDetector(data);
     281              :     }
     282       128898 : }
     283              : 
     284              : 
     285              : /*
     286              : void
     287              : MESegment::removeDetector(MSMoveReminder* data) {
     288              :     std::vector<MSMoveReminder*>::iterator it = std::find(myDetectorData.begin(), myDetectorData.end(), data);
     289              :     if (it != myDetectorData.end()) {
     290              :         myDetectorData.erase(it);
     291              :     }
     292              :     for (const Queue& q : myQueues) {
     293              :         for (MEVehicle* const v : q.getVehicles()) {
     294              :             v->removeReminder(data);
     295              :         }
     296              :     }
     297              : }
     298              : */
     299              : 
     300              : 
     301              : void
     302      6427852 : MESegment::prepareDetectorForWriting(MSMoveReminder& data, int queueIndex) {
     303      6427852 :     const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
     304      6427852 :     if (queueIndex == -1) {
     305     12882088 :         for (const Queue& q : myQueues) {
     306              :             SUMOTime earliestExitTime = currentTime;
     307      7761638 :             for (std::vector<MEVehicle*>::const_reverse_iterator i = q.getVehicles().rbegin(); i != q.getVehicles().rend(); ++i) {
     308      1306802 :                 const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
     309      1306802 :                 (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
     310      1306802 :                 earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
     311              :             }
     312              :         }
     313              :     } else {
     314              :         SUMOTime earliestExitTime = currentTime;
     315          612 :         for (std::vector<MEVehicle*>::const_reverse_iterator i = myQueues[queueIndex].getVehicles().rbegin(); i != myQueues[queueIndex].getVehicles().rend(); ++i) {
     316           12 :             const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
     317           12 :             (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
     318           12 :             earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
     319              :         }
     320              :     }
     321      6427852 : }
     322              : 
     323              : 
     324              : SUMOTime
     325    132241576 : MESegment::hasSpaceFor(const MEVehicle* const veh, const SUMOTime entryTime, int& qIdx, const bool init) const {
     326              :     SUMOTime earliestEntry = SUMOTime_MAX;
     327    132241576 :     qIdx = 0;
     328    132241576 :     if (myNumVehicles == 0 && myQueues.size() == 1) {
     329              :         // we have always space for at least one vehicle
     330     30438983 :         if (myQueues.front().allows(veh->getVClass())) {
     331              :             return entryTime;
     332              :         }  else {
     333              :             return earliestEntry;
     334              :         }
     335              :     }
     336    101802593 :     const SUMOVehicleClass svc = veh->getVClass();
     337              :     int minSize = std::numeric_limits<int>::max();
     338    102574390 :     const MSEdge* const succ = myNextSegment == nullptr ? veh->succEdge(veh->getEdge() == &myEdge ? 1 : 2) : nullptr;
     339    276278514 :     for (int i = 0; i < (int)myQueues.size(); i++) {
     340    174475921 :         const Queue& q = myQueues[i];
     341    174475921 :         const double newOccupancy = q.size() == 0 ? 0. : q.getOccupancy() + veh->getVehicleType().getLengthWithGap();
     342    174475921 :         if (newOccupancy <= myQueueCapacity) { // we must ensure that occupancy remains below capacity
     343     60615375 :             if (succ == nullptr || myFollowerMap.count(succ) == 0 || ((myFollowerMap.find(succ)->second & (1 << i)) != 0)) {
     344     41817855 :                 if (q.allows(svc) && q.size() < minSize) {
     345     26605119 :                     if (init) {
     346              :                         // regular insertions and initial insertions must respect different constraints:
     347      8222759 :                         if (veh->getInsertionChecks() == (int)InsertionCheck::NONE || hasSpaceForInsertion(q, i, newOccupancy, entryTime)) {
     348      4984999 :                             qIdx = i;
     349              :                             minSize = q.size();
     350              :                         }
     351     18382360 :                     } else if (entryTime >= q.getEntryBlockTime()) {
     352     18110737 :                         qIdx = i;
     353              :                         minSize = q.size();
     354              :                     } else {
     355              :                         earliestEntry = MIN2(earliestEntry, q.getEntryBlockTime());
     356              :                     }
     357              :                 }
     358              :             }
     359              :         }
     360              :     }
     361    101802593 :     if (minSize == std::numeric_limits<int>::max()) {
     362              :         return earliestEntry;
     363              :     }
     364              :     return entryTime;
     365              : }
     366              : 
     367              : 
     368              : bool
     369      8222715 : MESegment::hasSpaceForInsertion(const Queue& q, int /*qIdx*/, double newOccupancy, SUMOTime /*entryTime*/) const {
     370              :     // - regular insertions must respect entryBlockTime
     371              :     // - initial insertions should not cause additional jamming
     372              :     // - inserted vehicle should be able to continue at the current speed
     373      8222715 :     if (q.getOccupancy() <= myJamThreshold && !hasBlockedLeader() && !myTLSPenalty) {
     374      3988812 :         return newOccupancy <= myJamThreshold;
     375              :     } else {
     376      4233903 :         return newOccupancy <= jamThresholdForSpeed(getMeanSpeed(false), -1);
     377              :     }
     378              : }
     379              : 
     380              : 
     381              : bool
     382     12463447 : MESegment::initialise(MEVehicle* veh, SUMOTime time) {
     383     12463447 :     int qIdx = 0;
     384     12463447 :     if (hasSpaceFor(veh, time, qIdx, true) == time) {
     385     10548132 :         const bool isRail = veh->isRail();
     386              :         // see MSLane::isInsertionSuccess
     387      9708853 :         if (isRail && veh->getInsertionChecks() != (int)InsertionCheck::NONE
     388      9708834 :                 && veh->getParameter().departProcedure != DepartDefinition::SPLIT
     389      9708834 :                 && MSRailSignalControl::isSignalized(veh->getVClass())
     390     20256957 :                 && isRailwayOrShared(myEdge.getPermissions())) {
     391      9708819 :             const MSDriveWay* dw = MSDriveWay::getDepartureDriveway(veh);
     392              :             MSEdgeVector occupied;
     393      9708819 :             if (dw->foeDriveWayOccupied(false, veh, occupied)) {
     394      9706621 :                 myEdge.getLanes()[0]->setParameter("insertionBlocked:" + veh->getID(), dw->getID());
     395              :                 return false;
     396              :             }
     397      9708819 :         }
     398       841511 :         receive(veh, qIdx, time, true);
     399       841511 :         if (isRail) {
     400         4464 :             myEdge.getLanes()[0]->unsetParameter("insertionConstraint:" + veh->getID());
     401              :             //unsetParameter("insertionOrder:" + veh->getID());
     402              :             //unsetParameter("insertionBlocked:" + veh->getID());
     403              :             //// rail_signal (not traffic_light) requires approach information for
     404              :             //// switching correctly at the start of the next simulation step
     405              :             //if (firstRailSignal != nullptr && firstRailSignal->getJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
     406              :             //    veh->registerInsertionApproach(firstRailSignal, firstRailSignalDist);
     407              :             //}
     408              :         }
     409              :         // we can check only after insertion because insertion may change the route via devices
     410              :         std::string msg;
     411      1682274 :         if (MSGlobals::gCheckRoutes && !veh->hasValidRoute(msg)) {
     412            6 :             throw ProcessError(TLF("Vehicle '%' has no valid route. %", veh->getID(), msg));
     413              :         }
     414              :         return true;
     415              :     }
     416              :     return false;
     417              : }
     418              : 
     419              : 
     420              : double
     421     29726034 : MESegment::getMeanSpeed(bool useCached) const {
     422     29726034 :     const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
     423     29726034 :     if (currentTime != myLastMeanSpeedUpdate || !useCached) {
     424     29623704 :         myLastMeanSpeedUpdate = currentTime;
     425              :         double v = 0;
     426              :         int count = 0;
     427     61412300 :         for (const Queue& q : myQueues) {
     428     31788596 :             const SUMOTime tau = q.getOccupancy() < myJamThreshold ? myTau_ff : myTau_jf;
     429     31788596 :             SUMOTime earliestExitTime = currentTime;
     430     31788596 :             count += q.size();
     431    186567288 :             for (std::vector<MEVehicle*>::const_reverse_iterator veh = q.getVehicles().rbegin(); veh != q.getVehicles().rend(); ++veh) {
     432    154778692 :                 v += (*veh)->getConservativeSpeed(earliestExitTime); // earliestExitTime is updated!
     433    154778692 :                 earliestExitTime += tauWithVehLength(tau, (*veh)->getVehicleType().getLengthWithGap(), (*veh)->getVehicleType().getCarFollowModel().getHeadwayTime());
     434              :             }
     435              :         }
     436     29623704 :         if (count == 0) {
     437           30 :             myMeanSpeed = myEdge.getSpeedLimit();
     438              :         } else {
     439     29623674 :             myMeanSpeed = v / (double) count;
     440              :         }
     441              :     }
     442     29726034 :     return myMeanSpeed;
     443              : }
     444              : 
     445              : 
     446              : void
     447         5226 : MESegment::resetCachedSpeeds() {
     448         5226 :     myLastMeanSpeedUpdate = SUMOTime_MIN;
     449         5226 : }
     450              : 
     451              : void
     452        11953 : MESegment::writeVehicles(OutputDevice& of) const {
     453        24082 :     for (const Queue& q : myQueues) {
     454        14162 :         for (const MEVehicle* const veh : q.getVehicles()) {
     455         2033 :             MSXMLRawOut::writeVehicle(of, *veh);
     456              :         }
     457              :     }
     458        11953 : }
     459              : 
     460              : 
     461              : MEVehicle*
     462     26735627 : MESegment::removeCar(MEVehicle* v, SUMOTime leaveTime, const MSMoveReminder::Notification reason) {
     463     26735627 :     Queue& q = myQueues[v->getQueIndex()];
     464              :     // One could be tempted to do  v->setSegment(next); here but position on lane will be invalid if next == 0
     465     26735627 :     v->updateDetectors(leaveTime, v->getEventTime(), true, reason);
     466     26735627 :     myNumVehicles--;
     467     26735627 :     myEdge.lock();
     468     26735627 :     MEVehicle* nextLeader = q.remove(v);
     469     26735627 :     myEdge.invalidateMesoCache();
     470     26735627 :     myEdge.unlock();
     471     26735627 :     return nextLeader;
     472              : }
     473              : 
     474              : 
     475              : SUMOTime
     476        13655 : MESegment::getNextInsertionTime(SUMOTime earliestEntry) const {
     477              :     // since we do not know which queue will be used we give a conservative estimate
     478              :     SUMOTime earliestLeave = earliestEntry;
     479              :     SUMOTime latestEntry = -1;
     480        27575 :     for (const Queue& q : myQueues) {
     481              :         earliestLeave = MAX2(earliestLeave, q.getBlockTime());
     482              :         latestEntry = MAX2(latestEntry, q.getEntryBlockTime());
     483              :     }
     484        13655 :     if (myEdge.getSpeedLimit() == 0) {
     485           12 :         return MAX2(earliestEntry, latestEntry);    // FIXME: This line is just an adhoc-fix to avoid division by zero (Leo)
     486              :     } else {
     487        13643 :         return MAX3(earliestEntry, earliestLeave - TIME2STEPS(myLength / myEdge.getSpeedLimit()), latestEntry);
     488              :     }
     489              : }
     490              : 
     491              : 
     492              : MSLink*
     493    130480890 : MESegment::getLink(const MEVehicle* veh, bool penalty) const {
     494    130480890 :     if (myJunctionControl || penalty) {
     495     32802341 :         const MSEdge* const nextEdge = veh->succEdge(1);
     496     32802341 :         if (nextEdge == nullptr || veh->getQueIndex() == PARKING_QUEUE) {
     497              :             return nullptr;
     498              :         }
     499              :         // try to find any link leading to our next edge, start with the lane pointed to by the que index
     500     31455162 :         const MSLane* const bestLane = myEdge.getLanes()[veh->getQueIndex()];
     501     35844389 :         for (MSLink* const link : bestLane->getLinkCont()) {
     502     35430018 :             if (&link->getLane()->getEdge() == nextEdge) {
     503              :                 return link;
     504              :             }
     505              :         }
     506              :         // this is for the non-multique case, maybe we should use caching here !!!
     507       941320 :         for (const MSLane* const lane : myEdge.getLanes()) {
     508       924665 :             if (lane != bestLane) {
     509       643890 :                 for (MSLink* const link : lane->getLinkCont()) {
     510       529548 :                     if (&link->getLane()->getEdge() == nextEdge) {
     511              :                         return link;
     512              :                     }
     513              :                 }
     514              :             }
     515              :         }
     516              :     }
     517              :     return nullptr;
     518              : }
     519              : 
     520              : 
     521              : bool
     522     36637848 : MESegment::isOpen(const MEVehicle* veh) const {
     523              : #ifdef DEBUG_OPENED
     524              :     if (DEBUG_COND || DEBUG_COND2(veh)) {
     525              :         gDebugFlag1 = true;
     526              :         std::cout << SIMTIME << " opened seg=" << getID() << " veh=" << Named::getIDSecure(veh)
     527              :                   << " tlsPenalty=" << myTLSPenalty;
     528              :         const MSLink* link = getLink(veh);
     529              :         if (link == 0) {
     530              :             std::cout << " link=0";
     531              :         } else {
     532              :             std::cout << " prio=" << link->havePriority()
     533              :                       << " override=" << limitedControlOverride(link)
     534              :                       << " isOpen=" << link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
     535              :                                                     veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
     536              :                                                     veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime(),
     537              :                                                     0, nullptr, false, veh)
     538              :                       << " et=" << veh->getEventTime()
     539              :                       << " v=" << veh->getSpeed()
     540              :                       << " vLeave=" << veh->estimateLeaveSpeed(link)
     541              :                       << " impatience=" << veh->getImpatience()
     542              :                       << " tWait=" << veh->getWaitingTime();
     543              :         }
     544              :         std::cout << "\n";
     545              :         gDebugFlag1 = false;
     546              :     }
     547              : #endif
     548     36637848 :     if (myTLSPenalty) {
     549              :         // XXX should limited control take precedence over tls penalty?
     550              :         return true;
     551              :     }
     552     36585700 :     const MSLink* link = getLink(veh);
     553              :     return (link == nullptr
     554     12767475 :             || link->havePriority()
     555     11011117 :             || limitedControlOverride(link)
     556     47595629 :             || link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
     557     11009929 :                             veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
     558     11009929 :                             veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime(),
     559              :                             0, nullptr, false, veh));
     560              : }
     561              : 
     562              : 
     563              : bool
     564     11015329 : MESegment::limitedControlOverride(const MSLink* link) const {
     565              :     assert(link != nullptr);
     566     11015329 :     if (!MSGlobals::gMesoLimitedJunctionControl) {
     567              :         return false;
     568              :     }
     569              :     // if the target segment of this link is not saturated junction control is disabled
     570              :     const MSEdge& targetEdge = link->getLane()->getEdge();
     571        11236 :     const MESegment* target = MSGlobals::gMesoNet->getSegmentForEdge(targetEdge);
     572        11236 :     return (target->getBruttoOccupancy() * 2 < target->myJamThreshold) && !targetEdge.isRoundabout();
     573              : }
     574              : 
     575              : 
     576              : SUMOTime
     577     25932436 : MESegment::computeHeadway(Queue& /*q*/, const Queue& qNext, const MESegment* const next, const MEVehicle* veh) const {
     578     25932436 :     const bool nextFree = qNext.getOccupancy() <= next->myJamThreshold;
     579              :     const SUMOTime tau = (!veh->wasJammed()
     580     25932436 :             ? (nextFree ? myTau_ff : myTau_fj)
     581       726287 :             : (nextFree ? myTau_jf : getTauJJ((double)qNext.size(), next->myQueueCapacity, next->myJamThreshold)));
     582              :     assert(tau >= 0);
     583     25932436 :     SUMOTime headway = tauWithVehLength(tau, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime());
     584     25932436 :     if (myTLSPenalty) {
     585        52148 :         const MSLink* const tllink = getLink(veh, true);
     586        52148 :         if (tllink != nullptr && tllink->isTLSControlled()) {
     587              :             assert(tllink->getGreenFraction() > 0);
     588        49540 :             headway = (SUMOTime)((double)headway / tllink->getGreenFraction());
     589              :         }
     590              :     }
     591     25932436 :     return headway;
     592              : }
     593              : 
     594              : 
     595              : void
     596     26735627 : MESegment::send(MEVehicle* veh, MESegment* const next, const int nextQIdx, SUMOTime time, const MSMoveReminder::Notification reason) {
     597     26735627 :     Queue& q = myQueues[veh->getQueIndex()];
     598              :     assert(isInvalid(next) || time >= q.getBlockTime());
     599     26735627 :     MSLink* const link = getLink(veh);
     600     26735627 :     if (link != nullptr) {
     601      2072876 :         link->removeApproaching(veh);
     602              :     }
     603     26735627 :     if (veh->isStopped()) {
     604         8507 :         veh->processStop();
     605              :     }
     606     26735627 :     MEVehicle* lc = removeCar(veh, time, reason); // new leaderCar
     607              :     q.setBlockTime(time);
     608     26735627 :     if (myEdge.isNormal() && myCapacity >= 22.5 ) {
     609     20445259 :         veh->markJammed(q.getOccupancy() > myJamThreshold);
     610              :     }
     611              :     if (!isInvalid(next)) {
     612     25932436 :         myLastHeadway = computeHeadway(q, next->myQueues[nextQIdx], next, veh);
     613     25932436 :         q.setBlockTime(time + myLastHeadway);
     614              :     }
     615     26735627 :     if (lc != nullptr) {
     616              :         lc->setEventTime(MAX2(lc->getEventTime(), q.getBlockTime()));
     617     18275661 :         MSGlobals::gMesoNet->addLeaderCar(lc, getLink(lc));
     618              :     }
     619     26735627 : }
     620              : 
     621              : 
     622              : SUMOTime
     623       191291 : MESegment::getTauJJ(double nextQueueSize, double nextQueueCapacity, double nextJamThreshold) const {
     624              :     // compute coefficients for the jam-jam headway function
     625              :     // this function models the effect that "empty space" needs to move
     626              :     // backwards through the downstream segment before the upstream segment may
     627              :     // send annother vehicle.
     628              :     // this allows jams to clear and move upstream.
     629              :     // the headway function f(x) depends on the number of vehicles in the
     630              :     // downstream segment x
     631              :     // f is a linear function that passes through the following fixed points:
     632              :     // f(n_jam_threshold) = tau_jf_withLength (for continuity)
     633              :     // f(headwayCapacity) = myTau_jj * headwayCapacity
     634              : 
     635       191291 :     const SUMOTime tau_jf_withLength = tauWithVehLength(myTau_jf, DEFAULT_VEH_LENGTH_WITH_GAP, 1.);
     636              :     // number of vehicles that fit into the NEXT queue (could be larger than expected with DEFAULT_VEH_LENGTH_WITH_GAP!)
     637       191291 :     const double headwayCapacity = MAX2(nextQueueSize, nextQueueCapacity / DEFAULT_VEH_LENGTH_WITH_GAP);
     638              :     // number of vehicles above which the NEXT queue is jammed
     639       191291 :     const double n_jam_threshold = headwayCapacity * nextJamThreshold / nextQueueCapacity;
     640              : 
     641              :     // slope a and axis offset b for the jam-jam headway function
     642              :     // solving f(x) = a * x + b
     643       191291 :     const double a = (STEPS2TIME(myTau_jj) * headwayCapacity - STEPS2TIME(tau_jf_withLength)) / (headwayCapacity - n_jam_threshold);
     644       191291 :     const double b = headwayCapacity * (STEPS2TIME(myTau_jj) - a);
     645              : 
     646              :     // it is only well defined for nextQueueSize >= n_jam_threshold (which may not be the case for longer vehicles), so we take the MAX
     647       191291 :     return TIME2STEPS(a * MAX2(nextQueueSize, n_jam_threshold) + b);
     648              : }
     649              : 
     650              : 
     651              : bool
     652      1207433 : MESegment::overtake() {
     653      1207457 :     return myOvertaking && RandHelper::rand() > (getBruttoOccupancy() / myCapacity);
     654              : }
     655              : 
     656              : 
     657              : void
     658     26783370 : MESegment::addReminders(MEVehicle* veh) const {
     659     26783370 :     if (veh->getQueIndex() != PARKING_QUEUE) {
     660     26777564 :         myQueues[veh->getQueIndex()].addReminders(veh);
     661              :     }
     662     26783370 : }
     663              : 
     664              : 
     665              : void
     666     26780248 : MESegment::receive(MEVehicle* veh, const int qIdx, SUMOTime time, const bool isDepart, const bool isTeleport, const bool newEdge) {
     667     26780248 :     const double speed = isDepart ? -1 : MAX2(veh->getSpeed(), MESO_MIN_SPEED); // on the previous segment
     668     26780248 :     veh->setSegment(this); // for arrival checking
     669              :     veh->setLastEntryTime(time);
     670              :     veh->setBlockTime(SUMOTime_MAX);
     671     26780248 :     if (!isDepart && (
     672              :                 // arrival on entering a new edge
     673      5065356 :                 (newEdge && myEdge.isNormal() && veh->moveRoutePointer())
     674              :                 // arrival on entering a new segment
     675     25938578 :                 || veh->hasArrived())) {
     676              :         // route has ended
     677        15398 :         veh->setEventTime(time + TIME2STEPS(myLength / speed)); // for correct arrival speed
     678        15398 :         addReminders(veh);
     679        15398 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
     680        30692 :         veh->updateDetectors(time, veh->getEventTime(), true,
     681        15398 :                              veh->getEdge()->isVaporizing() ? MSMoveReminder::NOTIFICATION_VAPORIZED_VAPORIZER : MSMoveReminder::NOTIFICATION_ARRIVED);
     682        15398 :         MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
     683        15398 :         return;
     684              :     }
     685              :     assert(veh->getEdge() == &getEdge() || getEdge().isInternal());
     686              :     // route continues
     687     26764850 :     Queue& q = myQueues[qIdx];
     688     26764850 :     const double maxSpeedOnEdge = veh->getEdge()->getLanes()[qIdx]->getVehicleMaxSpeed(veh);
     689              :     const double uspeed = MAX2(maxSpeedOnEdge, MESO_MIN_SPEED);
     690              :     std::vector<MEVehicle*>& cars = q.getModifiableVehicles();
     691              :     MEVehicle* newLeader = nullptr; // first vehicle in the current queue
     692     26764850 :     const SUMOTime stopTime = veh->checkStop(time);
     693     26764850 :     SUMOTime tleave = MAX2(stopTime + TIME2STEPS(myLength / uspeed) + getLinkPenalty(veh), q.getBlockTime());
     694     26764850 :     if (veh->isStopped()) {
     695        14958 :         myEdge.addWaiting(veh);
     696              :     }
     697     26764850 :     if (veh->isParking()) {
     698              :         // parking stops should take at least 1ms
     699         5806 :         veh->setEventTime(MAX2(stopTime, veh->getEventTime() + 1));
     700         5806 :         veh->setSegment(this, PARKING_QUEUE);
     701         5806 :         myEdge.getLanes()[0]->addParking(veh);  // TODO for GUI only
     702              :     } else {
     703     26759044 :         myEdge.lock();
     704     26759044 :         if (cars.empty()) {
     705      8460448 :             cars.push_back(veh);
     706              :             newLeader = veh;
     707              :         } else {
     708     18298596 :             SUMOTime leaderOut = cars[0]->getEventTime();
     709     18298596 :             if (!isDepart && leaderOut > tleave && overtake()) {
     710           20 :                 if (cars.size() == 1) {
     711            4 :                     MSGlobals::gMesoNet->removeLeaderCar(cars[0]);
     712              :                     newLeader = veh;
     713              :                 }
     714           20 :                 cars.insert(cars.begin() + 1, veh);
     715              :             } else {
     716     18298576 :                 tleave = MAX2(leaderOut + tauWithVehLength(myTau_ff, cars[0]->getVehicleType().getLengthWithGap(), cars[0]->getVehicleType().getCarFollowModel().getHeadwayTime()), tleave);
     717     18298576 :                 cars.insert(cars.begin(), veh);
     718              :             }
     719              :         }
     720     26759044 :         myEdge.invalidateMesoCache();
     721     26759044 :         myEdge.unlock();
     722     26759044 :         myNumVehicles++;
     723     26759044 :         if (!isDepart && !isTeleport) {
     724              :             // departs and teleports could take place anywhere on the edge so they should not block regular flow
     725              :             // the -1 facilitates interleaving of multiple streams
     726     25916958 :             q.setEntryBlockTime(time + tauWithVehLength(myTau_ff, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime()) - 1);
     727              :         }
     728     26759044 :         q.setOccupancy(MIN2(myQueueCapacity, q.getOccupancy() + veh->getVehicleType().getLengthWithGap()));
     729              :         veh->setEventTime(tleave);
     730              :         veh->setUnqueuedEventTime(tleave);
     731     26759044 :         veh->setSegment(this, qIdx);
     732              :     }
     733     26764850 :     addReminders(veh);
     734     26764850 :     if (isDepart) {
     735       841511 :         veh->onDepart();
     736       841511 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_DEPARTED);
     737     25923339 :     } else if (newEdge) {
     738      5065197 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
     739              :     } else {
     740     20858142 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_SEGMENT);
     741              :     }
     742     26764850 :     if (veh->isParking()) {
     743         5826 :         MSGlobals::gMesoNet->addLeaderCar(veh, nullptr);
     744              :     } else {
     745     26759024 :         if (newLeader != nullptr) {
     746      8460434 :             MSGlobals::gMesoNet->addLeaderCar(newLeader, getLink(newLeader));
     747              :         }
     748              :     }
     749              : }
     750              : 
     751              : 
     752              : bool
     753         8752 : MESegment::vaporizeAnyCar(SUMOTime currentTime, const MSDetectorFileOutput* filter) {
     754         9304 :     for (const Queue& q : myQueues) {
     755         8778 :         if (q.size() > 0) {
     756         8226 :             for (MEVehicle* const veh : q.getVehicles()) {
     757         8226 :                 if (filter->vehicleApplies(*veh)) {
     758         8226 :                     MSGlobals::gMesoNet->removeLeaderCar(veh);
     759         8226 :                     MSGlobals::gMesoNet->changeSegment(veh, currentTime + 1, &myVaporizationTarget, MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR);
     760              :                     return true;
     761              :                 }
     762              :             }
     763              :         }
     764              :     }
     765              :     return false;
     766              : }
     767              : 
     768              : 
     769              : void
     770          352 : MESegment::setSpeedForQueue(double newSpeed, SUMOTime currentTime, SUMOTime blockTime, const std::vector<MEVehicle*>& vehs) {
     771          352 :     MEVehicle* v = vehs.back();
     772              :     SUMOTime oldEarliestExitTime = currentTime;
     773              :     const SUMOTime oldExit = MAX2(oldEarliestExitTime, v->getEventTime());
     774          352 :     v->updateDetectors(currentTime, oldExit, false);
     775          352 :     oldEarliestExitTime = oldExit + tauWithVehLength(myTau_ff, v->getVehicleType().getLengthWithGap(), v->getVehicleType().getCarFollowModel().getHeadwayTime());
     776          352 :     SUMOTime newEvent = MAX2(newArrival(v, newSpeed, currentTime), blockTime);
     777          352 :     if (v->getEventTime() != newEvent) {
     778          330 :         MSGlobals::gMesoNet->removeLeaderCar(v);
     779              :         v->setEventTime(newEvent);
     780          330 :         MSGlobals::gMesoNet->addLeaderCar(v, getLink(v));
     781              :     }
     782         1075 :     for (std::vector<MEVehicle*>::const_reverse_iterator i = vehs.rbegin() + 1; i != vehs.rend(); ++i) {
     783          723 :         const SUMOTime oldExitTime = MAX2(oldEarliestExitTime, (*i)->getEventTime());
     784          723 :         (*i)->updateDetectors(currentTime, oldExitTime, false);
     785          723 :         const SUMOTime minTau = tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
     786          723 :         oldEarliestExitTime = oldExitTime + minTau;
     787          723 :         newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + minTau);
     788          723 :         (*i)->setEventTime(newEvent);
     789              :     }
     790          352 : }
     791              : 
     792              : 
     793              : SUMOTime
     794         1075 : MESegment::newArrival(const MEVehicle* const v, double newSpeed, SUMOTime currentTime) {
     795              :     // since speed is only an upper bound, pos may be too optimistic
     796         1075 :     const double pos = MIN2(myLength, STEPS2TIME(currentTime - v->getLastEntryTime()) * v->getSpeed());
     797              :     // traveltime may not be 0
     798         1075 :     double tt = (myLength - pos) / MAX2(newSpeed, MESO_MIN_SPEED);
     799         1075 :     return currentTime + MAX2(TIME2STEPS(tt), SUMOTime(1));
     800              : }
     801              : 
     802              : 
     803              : void
     804         1044 : MESegment::setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh, int qIdx) {
     805         1044 :     recomputeJamThreshold(jamThresh);
     806              :     //myTau_length = MAX2(MESO_MIN_SPEED, newSpeed) * myEdge.getLanes().size() / TIME2STEPS(1);
     807              :     int i = 0;
     808         2182 :     for (const Queue& q : myQueues) {
     809         1138 :         if (q.size() != 0) {
     810          386 :             if (qIdx == -1 || qIdx == i) {
     811          352 :                 setSpeedForQueue(newSpeed, currentTime, q.getBlockTime(), q.getVehicles());
     812              :             }
     813              :         }
     814         1138 :         i++;
     815              :     }
     816         1044 : }
     817              : 
     818              : 
     819              : SUMOTime
     820      2153000 : MESegment::getEventTime() const {
     821              :     SUMOTime result = SUMOTime_MAX;
     822      4594901 :     for (const Queue& q : myQueues) {
     823      2441901 :         if (q.size() != 0 && q.getVehicles().back()->getEventTime() < result) {
     824              :             result = q.getVehicles().back()->getEventTime();
     825              :         }
     826              :     }
     827      2153000 :     if (result < SUMOTime_MAX) {
     828      1041011 :         return result;
     829              :     }
     830              :     return -1;
     831              : }
     832              : 
     833              : 
     834              : void
     835        11928 : MESegment::saveState(OutputDevice& out) const {
     836              :     bool write = false;
     837        23063 :     for (const Queue& q : myQueues) {
     838        12407 :         if (q.getBlockTime() != -1 || !q.getVehicles().empty()) {
     839              :             write = true;
     840              :             break;
     841              :         }
     842              :     }
     843        11928 :     if (write) {
     844         1272 :         out.openTag(SUMO_TAG_SEGMENT).writeAttr(SUMO_ATTR_ID, getID());
     845         2602 :         for (const Queue& q : myQueues) {
     846         1330 :             out.openTag(SUMO_TAG_VIEWSETTINGS_VEHICLES);
     847         1330 :             out.writeAttr(SUMO_ATTR_TIME, toString<SUMOTime>(q.getBlockTime()));
     848         1330 :             out.writeAttr(SUMO_ATTR_BLOCKTIME, toString<SUMOTime>(q.getEntryBlockTime()));
     849         1330 :             out.writeAttr(SUMO_ATTR_VALUE, q.getVehicles());
     850         2660 :             out.closeTag();
     851              :         }
     852         2544 :         out.closeTag();
     853              :     }
     854        11928 : }
     855              : 
     856              : 
     857              : void
     858          398 : MESegment::clearState() {
     859          836 :     for (Queue& q : myQueues) {
     860              :         q.getModifiableVehicles().clear();
     861              :     }
     862          398 : }
     863              : 
     864              : void
     865         1161 : MESegment::loadState(const std::vector<SUMOVehicle*>& vehs, const SUMOTime blockTime, const SUMOTime entryBlockTime, const int queIdx) {
     866         1161 :     Queue& q = myQueues[queIdx];
     867         1657 :     for (SUMOVehicle* veh : vehs) {
     868          496 :         MEVehicle* v = static_cast<MEVehicle*>(veh);
     869              :         assert(v->getSegment() == this || myEdge.isInternal());
     870          496 :         if (myEdge.isInternal()) {
     871           15 :             v->setSegment(this, v->getQueIndex());
     872              :         }
     873          496 :         q.getModifiableVehicles().push_back(v);
     874          496 :         myNumVehicles++;
     875          496 :         q.setOccupancy(q.getOccupancy() + v->getVehicleType().getLengthWithGap());
     876          496 :         addReminders(v);
     877              :     }
     878         1161 :     if (q.size() != 0) {
     879              :         // add the last vehicle of this queue
     880              :         // !!! one question - what about the previously added vehicle? Is it stored twice?
     881          257 :         MEVehicle* veh = q.getVehicles().back();
     882          257 :         MSGlobals::gMesoNet->addLeaderCar(veh, getLink(veh));
     883              :     }
     884              :     q.setBlockTime(blockTime);
     885              :     q.setEntryBlockTime(entryBlockTime);
     886         1161 :     q.setOccupancy(MIN2(q.getOccupancy(), myQueueCapacity));
     887         1161 : }
     888              : 
     889              : 
     890              : std::vector<const MEVehicle*>
     891          122 : MESegment::getVehicles() const {
     892              :     std::vector<const MEVehicle*> result;
     893          316 :     for (const Queue& q : myQueues) {
     894          194 :         result.insert(result.end(), q.getVehicles().begin(), q.getVehicles().end());
     895              :     }
     896          122 :     return result;
     897            0 : }
     898              : 
     899              : 
     900              : bool
     901      4021168 : MESegment::hasBlockedLeader() const {
     902      8094996 :     for (const Queue& q : myQueues) {
     903      4105910 :         if (q.size() > 0 && q.getVehicles().back()->getWaitingTime() > 0) {
     904              :             return true;
     905              :         }
     906              :     }
     907              :     return false;
     908              : }
     909              : 
     910              : 
     911              : double
     912            0 : MESegment::getFlow() const {
     913            0 :     return 3600 * getCarNumber() * getMeanSpeed() / myLength;
     914              : }
     915              : 
     916              : 
     917              : SUMOTime
     918     26764850 : MESegment::getLinkPenalty(const MEVehicle* veh) const {
     919     26764850 :     const MSLink* link = getLink(veh, myTLSPenalty || myCheckMinorPenalty);
     920     26764850 :     if (link != nullptr) {
     921              :         SUMOTime result = 0;
     922      2127715 :         if (link->isTLSControlled() && myTLSPenalty) {
     923              :             result += link->getMesoTLSPenalty();
     924              :         }
     925              :         // minor tls links may get an additional penalty
     926       419995 :         if (!link->havePriority() &&
     927              :                 // do not apply penalty on top of tLSPenalty
     928      2127715 :                 !myTLSPenalty &&
     929              :                 // do not apply penalty if limited control is active
     930       384113 :                 (!MSGlobals::gMesoLimitedJunctionControl || limitedControlOverride(link))) {
     931       380991 :             result += myMinorPenalty;
     932              :         }
     933      2127715 :         return result;
     934              :     } else {
     935              :         return 0;
     936              :     }
     937              : }
     938              : 
     939              : 
     940              : double
     941            9 : MESegment::getWaitingSeconds() const {
     942              :     double result = 0;
     943           22 :     for (const Queue& q : myQueues) {
     944              :         // @note: only the leader currently accumulates waitingTime but this might change in the future
     945           16 :         for (const MEVehicle* veh : q.getVehicles()) {
     946            3 :             result += veh->getWaitingSeconds();
     947              :         }
     948              :     }
     949            9 :     return result;
     950              : }
     951              : 
     952              : 
     953              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1