LCOV - code coverage report
Current view: top level - src/mesosim - MESegment.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 364 369 98.6 %
Date: 2024-04-27 15:34:54 Functions: 37 38 97.4 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
       4             : // This program and the accompanying materials are made available under the
       5             : // terms of the Eclipse Public License 2.0 which is available at
       6             : // https://www.eclipse.org/legal/epl-2.0/
       7             : // This Source Code may also be made available under the following Secondary
       8             : // Licenses when the conditions for such availability set forth in the Eclipse
       9             : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10             : // or later which is available at
      11             : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12             : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13             : /****************************************************************************/
      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/output/MSXMLRawOut.h>
      33             : #include <microsim/output/MSDetectorFileOutput.h>
      34             : #include <microsim/MSVehicleControl.h>
      35             : #include <microsim/devices/MSDevice.h>
      36             : #include <utils/common/FileHelpers.h>
      37             : #include <utils/iodevices/OutputDevice.h>
      38             : #include <utils/common/RandHelper.h>
      39             : #include "MEVehicle.h"
      40             : #include "MELoop.h"
      41             : #include "MESegment.h"
      42             : 
      43             : #define DEFAULT_VEH_LENGTH_WITH_GAP (SUMOVTypeParameter::getDefault().length + SUMOVTypeParameter::getDefault().minGap)
      44             : // avoid division by zero when driving very slowly
      45             : #define MESO_MIN_SPEED (0.05)
      46             : 
      47             : //#define DEBUG_OPENED
      48             : //#define DEBUG_JAMTHRESHOLD
      49             : //#define DEBUG_COND (getID() == "blocker")
      50             : //#define DEBUG_COND (true)
      51             : #define DEBUG_COND (myEdge.isSelected())
      52             : #define DEBUG_COND2(obj) ((obj != 0 && (obj)->isSelected()))
      53             : 
      54             : 
      55             : // ===========================================================================
      56             : // static member definition
      57             : // ===========================================================================
      58             : MSEdge MESegment::myDummyParent("MESegmentDummyParent", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", -1, 0);
      59             : MESegment MESegment::myVaporizationTarget("vaporizationTarget");
      60             : const double MESegment::DO_NOT_PATCH_JAM_THRESHOLD(std::numeric_limits<double>::max());
      61             : 
      62             : 
      63             : // ===========================================================================
      64             : // MESegment::Queue method definitions
      65             : // ===========================================================================
      66             : MEVehicle*
      67    33757994 : MESegment::Queue::remove(MEVehicle* v) {
      68    33757994 :     myOccupancy -= v->getVehicleType().getLengthWithGap();
      69             :     assert(std::find(myVehicles.begin(), myVehicles.end(), v) != myVehicles.end());
      70    33757994 :     if (v == myVehicles.back()) {
      71             :         myVehicles.pop_back();
      72    33751715 :         if (myVehicles.empty()) {
      73    11668425 :             myOccupancy = 0.;
      74             :         } else {
      75    22083290 :             return myVehicles.back();
      76             :         }
      77             :     } else {
      78        6279 :         myVehicles.erase(std::find(myVehicles.begin(), myVehicles.end(), v));
      79             :     }
      80             :     return nullptr;
      81             : }
      82             : 
      83             : void
      84      119963 : MESegment::Queue::addDetector(MSMoveReminder* data) {
      85      119963 :     myDetectorData.push_back(data);
      86      125401 :     for (MEVehicle* const v : myVehicles) {
      87        5438 :         v->addReminder(data);
      88             :     }
      89      119963 : }
      90             : 
      91             : void
      92    33795048 : MESegment::Queue::addReminders(MEVehicle* veh) const {
      93    43105891 :     for (MSMoveReminder* rem : myDetectorData) {
      94     9310843 :         veh->addReminder(rem);
      95             :     }
      96    33795048 : }
      97             : 
      98             : // ===========================================================================
      99             : // MESegment method definitions
     100             : // ===========================================================================
     101      608891 : MESegment::MESegment(const std::string& id,
     102             :                      const MSEdge& parent, MESegment* next,
     103             :                      const double length, const double speed,
     104             :                      const int idx,
     105             :                      const bool multiQueue,
     106      608891 :                      const MesoEdgeType& edgeType):
     107      608891 :     Named(id), myEdge(parent), myNextSegment(next),
     108      608891 :     myLength(length), myIndex(idx),
     109      608891 :     myTau_length(TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, speed)),
     110      608891 :     myNumVehicles(0),
     111      608891 :     myLastHeadway(TIME2STEPS(-1)),
     112      608891 :     myMeanSpeed(speed),
     113     1217539 :     myLastMeanSpeedUpdate(SUMOTime_MIN) {
     114             : 
     115             :     const std::vector<MSLane*>& lanes = parent.getLanes();
     116             :     int usableLanes = 0;
     117     1307765 :     for (MSLane* const l : lanes) {
     118      698874 :         const SVCPermissions allow = MSEdge::getMesoPermissions(l->getPermissions());
     119      698874 :         if (multiQueue) {
     120       30375 :             myQueues.push_back(Queue(allow));
     121             :         }
     122      698874 :         if (allow != 0) {
     123      672612 :             usableLanes++;
     124             :         }
     125             :     }
     126      608891 :     if (multiQueue) {
     127       13552 :         if (next == nullptr) {
     128       56542 :             for (const MSEdge* const edge : parent.getSuccessors()) {
     129       43320 :                 const std::vector<MSLane*>* const allowed = parent.allowedLanes(*edge);
     130             :                 assert(allowed != nullptr);
     131             :                 assert(allowed->size() > 0);
     132       92615 :                 for (MSLane* const l : *allowed) {
     133       49295 :                     std::vector<MSLane*>::const_iterator it = std::find(lanes.begin(), lanes.end(), l);
     134       49295 :                     myFollowerMap[edge] |= (1 << distance(lanes.begin(), it));
     135             :                 }
     136             :             }
     137             :         }
     138       13552 :         myQueueCapacity = length;
     139             :     } else {
     140      595339 :         myQueues.push_back(Queue(parent.getPermissions()));
     141             :     }
     142             : 
     143      608891 :     initSegment(edgeType, parent, length * usableLanes);
     144      608891 : }
     145             : 
     146             : void
     147      609131 : MESegment::initSegment(const MesoEdgeType& edgeType, const MSEdge& parent, const double capacity) {
     148             : 
     149      609131 :     myCapacity = capacity;
     150      609131 :     if (myQueues.size() == 1) {
     151      595963 :         const double laneScale = capacity / myLength;
     152      595963 :         myQueueCapacity = capacity;
     153      595963 :         myTau_length = TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, myMeanSpeed) / laneScale;
     154             :         // Eissfeldt p. 90 and 151 ff.
     155      595963 :         myTau_ff = (SUMOTime)((double)edgeType.tauff / laneScale);
     156      595963 :         myTau_fj = (SUMOTime)((double)edgeType.taufj / laneScale);
     157      595963 :         myTau_jf = (SUMOTime)((double)edgeType.taujf / laneScale);
     158      595963 :         myTau_jj = (SUMOTime)((double)edgeType.taujj / laneScale);
     159             :     } else {
     160       13168 :         myTau_ff = edgeType.tauff;
     161       13168 :         myTau_fj = edgeType.taufj;
     162       13168 :         myTau_jf = edgeType.taujf;
     163       13168 :         myTau_jj = edgeType.taujj;
     164             :     }
     165             : 
     166      609131 :     myJunctionControl = myNextSegment == nullptr && (edgeType.junctionControl || MELoop::isEnteringRoundabout(parent));
     167      608483 :     myTLSPenalty = ((edgeType.tlsPenalty > 0 || edgeType.tlsFlowPenalty > 0) &&
     168             :                     // only apply to the last segment of a tls-controlled edge
     169      609407 :                     myNextSegment == nullptr && (
     170         206 :                         parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT ||
     171         206 :                         parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION ||
     172             :                         parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED));
     173             : 
     174             :     // only apply to the last segment of an uncontrolled edge that has at least 1 minor link
     175     1218582 :     myCheckMinorPenalty = (edgeType.minorPenalty > 0 &&
     176         320 :                            myNextSegment == nullptr &&
     177         178 :                            parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT &&
     178         178 :                            parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION &&
     179      609309 :                            parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
     180         178 :                            parent.hasMinorLink());
     181      609131 :     myMinorPenalty = edgeType.minorPenalty;
     182      609131 :     myOvertaking = edgeType.overtaking && myCapacity > myLength;
     183             : 
     184             :     //std::cout << getID() << " myMinorPenalty=" << myMinorPenalty << " myTLSPenalty=" << myTLSPenalty << " myJunctionControl=" << myJunctionControl << " myOvertaking=" << myOvertaking << "\n";
     185             : 
     186      609131 :     recomputeJamThreshold(edgeType.jamThreshold);
     187      609131 : }
     188             : 
     189       36277 : MESegment::MESegment(const std::string& id):
     190             :     Named(id),
     191       36277 :     myEdge(myDummyParent), // arbitrary edge needed to supply the needed reference
     192       36277 :     myNextSegment(nullptr), myLength(0), myIndex(0),
     193       36277 :     myTau_ff(0), myTau_fj(0), myTau_jf(0), myTau_jj(0),
     194       36277 :     myTLSPenalty(false),
     195       36277 :     myCheckMinorPenalty(false),
     196       36277 :     myMinorPenalty(0),
     197       36277 :     myJunctionControl(false),
     198       36277 :     myOvertaking(false),
     199       36277 :     myTau_length(1) {
     200       36277 : }
     201             : 
     202             : 
     203             : void
     204        1126 : MESegment::updatePermissions() {
     205        1126 :     if (myQueues.size() > 1) {
     206          64 :         for (MSLane* lane : myEdge.getLanes()) {
     207          48 :             myQueues[lane->getIndex()].setPermissions(lane->getPermissions());
     208             :         }
     209             :     } else {
     210        1110 :         myQueues.back().setPermissions(myEdge.getPermissions());
     211             :     }
     212        1126 : }
     213             : 
     214             : 
     215             : void
     216      610102 : MESegment::recomputeJamThreshold(double jamThresh) {
     217      610102 :     if (jamThresh == DO_NOT_PATCH_JAM_THRESHOLD) {
     218             :         return;
     219             :     }
     220      610102 :     if (jamThresh < 0) {
     221             :         // compute based on speed
     222      610098 :         myJamThreshold = jamThresholdForSpeed(myEdge.getSpeedLimit(), jamThresh);
     223             :     } else {
     224             :         // compute based on specified percentage
     225           4 :         myJamThreshold = jamThresh * myCapacity;
     226             :     }
     227             : }
     228             : 
     229             : 
     230             : double
     231     3984947 : MESegment::jamThresholdForSpeed(double speed, double jamThresh) const {
     232             :     // vehicles driving freely at maximum speed should not jam
     233             :     // we compute how many vehicles could possible enter the segment until the first vehicle leaves
     234             :     // and multiply by the space these vehicles would occupy
     235             :     // the jamThresh parameter is scale the resulting value
     236     3984947 :     if (speed == 0) {
     237             :         return std::numeric_limits<double>::max();  // never jam. Irrelevant at speed 0 anyway
     238             :     }
     239             : #ifdef DEBUG_JAMTHRESHOLD
     240             :     if (true || DEBUG_COND) {
     241             :         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
     242             :                   << "\n";
     243             :     }
     244             : #endif
     245     3984726 :     return std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGTH_WITH_GAP, 1.)))) * DEFAULT_VEH_LENGTH_WITH_GAP;
     246             : }
     247             : 
     248             : 
     249             : void
     250      118417 : MESegment::addDetector(MSMoveReminder* data, int queueIndex) {
     251      118417 :     if (queueIndex == -1) {
     252      237888 :         for (Queue& q : myQueues) {
     253      119717 :             q.addDetector(data);
     254             :         }
     255             :     } else {
     256             :         assert(queueIndex < (int)myQueues.size());
     257         246 :         myQueues[queueIndex].addDetector(data);
     258             :     }
     259      118417 : }
     260             : 
     261             : 
     262             : /*
     263             : void
     264             : MESegment::removeDetector(MSMoveReminder* data) {
     265             :     std::vector<MSMoveReminder*>::iterator it = std::find(myDetectorData.begin(), myDetectorData.end(), data);
     266             :     if (it != myDetectorData.end()) {
     267             :         myDetectorData.erase(it);
     268             :     }
     269             :     for (const Queue& q : myQueues) {
     270             :         for (MEVehicle* const v : q.getVehicles()) {
     271             :             v->removeReminder(data);
     272             :         }
     273             :     }
     274             : }
     275             : */
     276             : 
     277             : 
     278             : void
     279     6379450 : MESegment::prepareDetectorForWriting(MSMoveReminder& data, int queueIndex) {
     280     6379450 :     const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
     281     6379450 :     if (queueIndex == -1) {
     282    12829568 :         for (const Queue& q : myQueues) {
     283             :             SUMOTime earliestExitTime = currentTime;
     284     7820000 :             for (std::vector<MEVehicle*>::const_reverse_iterator i = q.getVehicles().rbegin(); i != q.getVehicles().rend(); ++i) {
     285     1369390 :                 const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
     286     1369390 :                 (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
     287     1369390 :                 earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
     288             :             }
     289             :         }
     290             :     } else {
     291             :         SUMOTime earliestExitTime = currentTime;
     292         492 :         for (std::vector<MEVehicle*>::const_reverse_iterator i = myQueues[queueIndex].getVehicles().rbegin(); i != myQueues[queueIndex].getVehicles().rend(); ++i) {
     293           0 :             const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
     294           0 :             (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
     295           0 :             earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
     296             :         }
     297             :     }
     298     6379450 : }
     299             : 
     300             : 
     301             : SUMOTime
     302    69888042 : MESegment::hasSpaceFor(const MEVehicle* const veh, const SUMOTime entryTime, int& qIdx, const bool init) const {
     303             :     SUMOTime earliestEntry = SUMOTime_MAX;
     304    69888042 :     qIdx = 0;
     305    69888042 :     if (myNumVehicles == 0 && myQueues.size() == 1) {
     306             :         // we have always space for at least one vehicle
     307    18935178 :         if (myQueues.front().allows(veh->getVClass())) {
     308             :             return entryTime;
     309             :         }  else {
     310      237717 :             return earliestEntry;
     311             :         }
     312             :     }
     313    50952864 :     const SUMOVehicleClass svc = veh->getVClass();
     314             :     int minSize = std::numeric_limits<int>::max();
     315    50952864 :     const MSEdge* const succ = myNextSegment == nullptr ? veh->succEdge(1) : nullptr;
     316   103360819 :     for (int i = 0; i < (int)myQueues.size(); i++) {
     317    52407955 :         const Queue& q = myQueues[i];
     318    52407955 :         const double newOccupancy = q.size() == 0 ? 0. : q.getOccupancy() + veh->getVehicleType().getLengthWithGap();
     319    52407955 :         if (newOccupancy <= myQueueCapacity) { // we must ensure that occupancy remains below capacity
     320    31671963 :             if (succ == nullptr || myFollowerMap.count(succ) == 0 || ((myFollowerMap.find(succ)->second & (1 << i)) != 0)) {
     321    29941568 :                 if (q.allows(svc) && q.size() < minSize) {
     322    29501722 :                     if (init) {
     323             :                         // regular insertions and initial insertions must respect different constraints:
     324             :                         // - regular insertions must respect entryBlockTime
     325             :                         // - initial insertions should not cause additional jamming
     326             :                         // - inserted vehicle should be able to continue at the current speed
     327     7051465 :                         if (q.getOccupancy() <= myJamThreshold && !hasBlockedLeader() && !myTLSPenalty) {
     328     3676616 :                             if (newOccupancy <= myJamThreshold) {
     329     1327000 :                                 qIdx = i;
     330             :                                 minSize = q.size();
     331             :                             }
     332             :                         } else {
     333     3374849 :                             if (newOccupancy <= jamThresholdForSpeed(getMeanSpeed(false), -1)) {
     334     2611865 :                                 qIdx = i;
     335             :                                 minSize = q.size();
     336             :                             }
     337             :                         }
     338    22450257 :                     } else if (entryTime >= q.getEntryBlockTime()) {
     339    22048792 :                         qIdx = i;
     340             :                         minSize = q.size();
     341             :                     } else {
     342             :                         earliestEntry = MIN2(earliestEntry, q.getEntryBlockTime());
     343             :                     }
     344             :                 }
     345             :             }
     346             :         }
     347             :     }
     348    50952864 :     if (minSize == std::numeric_limits<int>::max()) {
     349    25003579 :         return earliestEntry;
     350             :     }
     351             :     return entryTime;
     352             : }
     353             : 
     354             : 
     355             : bool
     356     2048073 : MESegment::initialise(MEVehicle* veh, SUMOTime time) {
     357     2048073 :     int qIdx = 0;
     358     2048073 :     if (hasSpaceFor(veh, time, qIdx, true) == time) {
     359      797652 :         receive(veh, qIdx, time, true);
     360             :         // we can check only after insertion because insertion may change the route via devices
     361             :         std::string msg;
     362     1594701 :         if (MSGlobals::gCheckRoutes && !veh->hasValidRoute(msg)) {
     363           4 :             throw ProcessError("Vehicle '" + veh->getID() + "' has no valid route. " + msg);
     364             :         }
     365             :         return true;
     366             :     }
     367             :     return false;
     368             : }
     369             : 
     370             : 
     371             : double
     372    48485921 : MESegment::getMeanSpeed(bool useCached) const {
     373    48485921 :     const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
     374    48485921 :     if (currentTime != myLastMeanSpeedUpdate || !useCached) {
     375    48393515 :         myLastMeanSpeedUpdate = currentTime;
     376             :         double v = 0;
     377             :         int count = 0;
     378    97136177 :         for (const Queue& q : myQueues) {
     379    48742662 :             const SUMOTime tau = q.getOccupancy() < myJamThreshold ? myTau_ff : myTau_jf;
     380    48742662 :             SUMOTime earliestExitTime = currentTime;
     381    48742662 :             count += q.size();
     382   200345816 :             for (std::vector<MEVehicle*>::const_reverse_iterator veh = q.getVehicles().rbegin(); veh != q.getVehicles().rend(); ++veh) {
     383   151603154 :                 v += (*veh)->getConservativeSpeed(earliestExitTime); // earliestExitTime is updated!
     384   151603154 :                 earliestExitTime += tauWithVehLength(tau, (*veh)->getVehicleType().getLengthWithGap(), (*veh)->getVehicleType().getCarFollowModel().getHeadwayTime());
     385             :             }
     386             :         }
     387    48393515 :         if (count == 0) {
     388          18 :             myMeanSpeed = myEdge.getSpeedLimit();
     389             :         } else {
     390    48393497 :             myMeanSpeed = v / (double) count;
     391             :         }
     392             :     }
     393    48485921 :     return myMeanSpeed;
     394             : }
     395             : 
     396             : 
     397             : void
     398      205994 : MESegment::writeVehicles(OutputDevice& of) const {
     399      412356 :     for (const Queue& q : myQueues) {
     400      220490 :         for (const MEVehicle* const veh : q.getVehicles()) {
     401       14128 :             MSXMLRawOut::writeVehicle(of, *veh);
     402             :         }
     403             :     }
     404      205994 : }
     405             : 
     406             : 
     407             : MEVehicle*
     408    33757994 : MESegment::removeCar(MEVehicle* v, SUMOTime leaveTime, const MSMoveReminder::Notification reason) {
     409    33757994 :     Queue& q = myQueues[v->getQueIndex()];
     410             :     // One could be tempted to do  v->setSegment(next); here but position on lane will be invalid if next == 0
     411    33757994 :     v->updateDetectors(leaveTime, true, reason);
     412    33757994 :     myNumVehicles--;
     413    33757994 :     myEdge.lock();
     414    33757994 :     MEVehicle* nextLeader = q.remove(v);
     415    33757994 :     myEdge.unlock();
     416    33757994 :     return nextLeader;
     417             : }
     418             : 
     419             : 
     420             : SUMOTime
     421       13548 : MESegment::getNextInsertionTime(SUMOTime earliestEntry) const {
     422             :     // since we do not know which queue will be used we give a conservative estimate
     423             :     SUMOTime earliestLeave = earliestEntry;
     424             :     SUMOTime latestEntry = -1;
     425       27354 :     for (const Queue& q : myQueues) {
     426             :         earliestLeave = MAX2(earliestLeave, q.getBlockTime());
     427             :         latestEntry = MAX2(latestEntry, q.getEntryBlockTime());
     428             :     }
     429       13548 :     if (myEdge.getSpeedLimit() == 0) {
     430          12 :         return MAX2(earliestEntry, latestEntry);    // FIXME: This line is just an adhoc-fix to avoid division by zero (Leo)
     431             :     } else {
     432       13536 :         return MAX3(earliestEntry, earliestLeave - TIME2STEPS(myLength / myEdge.getSpeedLimit()), latestEntry);
     433             :     }
     434             : }
     435             : 
     436             : 
     437             : MSLink*
     438   150855090 : MESegment::getLink(const MEVehicle* veh, bool penalty) const {
     439   150855090 :     if (myJunctionControl || penalty) {
     440    22564212 :         const MSEdge* const nextEdge = veh->succEdge(1);
     441    22564212 :         if (nextEdge == nullptr || veh->getQueIndex() == PARKING_QUEUE) {
     442             :             return nullptr;
     443             :         }
     444             :         // try to find any link leading to our next edge, start with the lane pointed to by the que index
     445    21496678 :         const MSLane* const bestLane = myEdge.getLanes()[veh->getQueIndex()];
     446    25922784 :         for (MSLink* const link : bestLane->getLinkCont()) {
     447    25453219 :             if (&link->getLane()->getEdge() == nextEdge) {
     448             :                 return link;
     449             :             }
     450             :         }
     451             :         // this is for the non-multique case, maybe we should use caching here !!!
     452      999339 :         for (const MSLane* const lane : myEdge.getLanes()) {
     453      999285 :             if (lane != bestLane) {
     454      777671 :                 for (MSLink* const link : lane->getLinkCont()) {
     455      659260 :                     if (&link->getLane()->getEdge() == nextEdge) {
     456             :                         return link;
     457             :                     }
     458             :                 }
     459             :             }
     460             :         }
     461             :     }
     462             :     return nullptr;
     463             : }
     464             : 
     465             : 
     466             : bool
     467    40322031 : MESegment::isOpen(const MEVehicle* veh) const {
     468             : #ifdef DEBUG_OPENED
     469             :     if (DEBUG_COND || DEBUG_COND2(veh)) {
     470             :         gDebugFlag1 = true;
     471             :         std::cout << SIMTIME << " opened seg=" << getID() << " veh=" << Named::getIDSecure(veh)
     472             :                   << " tlsPenalty=" << myTLSPenalty;
     473             :         const MSLink* link = getLink(veh);
     474             :         if (link == 0) {
     475             :             std::cout << " link=0";
     476             :         } else {
     477             :             std::cout << " prio=" << link->havePriority()
     478             :                       << " override=" << limitedControlOverride(link)
     479             :                       << " isOpen=" << link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
     480             :                                                     veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
     481             :                                                     veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime())
     482             :                       << " et=" << veh->getEventTime()
     483             :                       << " v=" << veh->getSpeed()
     484             :                       << " vLeave=" << veh->estimateLeaveSpeed(link)
     485             :                       << " impatience=" << veh->getImpatience()
     486             :                       << " tWait=" << veh->getWaitingTime();
     487             :         }
     488             :         std::cout << "\n";
     489             :         gDebugFlag1 = false;
     490             :     }
     491             : #endif
     492    40322031 :     if (myTLSPenalty) {
     493             :         // XXX should limited control take precedence over tls penalty?
     494             :         return true;
     495             :     }
     496    40273211 :     const MSLink* link = getLink(veh);
     497             :     return (link == nullptr
     498     8819652 :             || link->havePriority()
     499     7719301 :             || limitedControlOverride(link)
     500    47991748 :             || link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
     501     7718537 :                             veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
     502     7718537 :                             veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime()));
     503             : }
     504             : 
     505             : 
     506             : bool
     507     7722491 : MESegment::limitedControlOverride(const MSLink* link) const {
     508             :     assert(link != nullptr);
     509     7722491 :     if (!MSGlobals::gMesoLimitedJunctionControl) {
     510             :         return false;
     511             :     }
     512             :     // if the target segment of this link is not saturated junction control is disabled
     513             :     const MSEdge& targetEdge = link->getLane()->getEdge();
     514        8248 :     const MESegment* target = MSGlobals::gMesoNet->getSegmentForEdge(targetEdge);
     515        8248 :     return (target->getBruttoOccupancy() * 2 < target->myJamThreshold) && !targetEdge.isRoundabout();
     516             : }
     517             : 
     518             : 
     519             : void
     520    33757994 : MESegment::send(MEVehicle* veh, MESegment* const next, const int nextQIdx, SUMOTime time, const MSMoveReminder::Notification reason) {
     521    33757994 :     Queue& q = myQueues[veh->getQueIndex()];
     522             :     assert(isInvalid(next) || time >= q.getBlockTime());
     523    33757994 :     MSLink* const link = getLink(veh);
     524    33757994 :     if (link != nullptr) {
     525     1495344 :         link->removeApproaching(veh);
     526             :     }
     527    33757994 :     if (veh->isStopped()) {
     528        6948 :         veh->processStop();
     529             :     }
     530    33757994 :     MEVehicle* lc = removeCar(veh, time, reason); // new leaderCar
     531             :     q.setBlockTime(time);
     532             :     if (!isInvalid(next)) {
     533    32994868 :         const bool nextFree = next->myQueues[nextQIdx].getOccupancy() <= next->myJamThreshold;
     534    32994868 :         const SUMOTime tau = (q.getOccupancy() <= myJamThreshold
     535    32994868 :                               ? (nextFree ? myTau_ff : myTau_fj)
     536      437073 :                               : (nextFree ? myTau_jf : getTauJJ((double)next->myQueues[nextQIdx].size(), next->myQueueCapacity, next->myJamThreshold)));
     537             :         assert(tau >= 0);
     538    32994868 :         myLastHeadway = tauWithVehLength(tau, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime());
     539    32994868 :         if (myTLSPenalty) {
     540       48820 :             const MSLink* const tllink = getLink(veh, true);
     541       48820 :             if (tllink != nullptr && tllink->isTLSControlled()) {
     542             :                 assert(tllink->getGreenFraction() > 0);
     543       48820 :                 myLastHeadway = (SUMOTime)((double)myLastHeadway / tllink->getGreenFraction());
     544             :             }
     545             :         }
     546    32994868 :         q.setBlockTime(q.getBlockTime() + myLastHeadway);
     547             :     }
     548    33757994 :     if (lc != nullptr) {
     549             :         lc->setEventTime(MAX2(lc->getEventTime(), q.getBlockTime()));
     550    22083290 :         MSGlobals::gMesoNet->addLeaderCar(lc, getLink(lc));
     551             :     }
     552    33757994 : }
     553             : 
     554             : SUMOTime
     555      139296 : MESegment::getTauJJ(double nextQueueSize, double nextQueueCapacity, double nextJamThreshold) const {
     556             :     // compute coefficients for the jam-jam headway function
     557             :     // this function models the effect that "empty space" needs to move
     558             :     // backwards through the downstream segment before the upstream segment may
     559             :     // send annother vehicle.
     560             :     // this allows jams to clear and move upstream.
     561             :     // the headway function f(x) depends on the number of vehicles in the
     562             :     // downstream segment x
     563             :     // f is a linear function that passes through the following fixed points:
     564             :     // f(n_jam_threshold) = tau_jf_withLength (for continuity)
     565             :     // f(headwayCapacity) = myTau_jj * headwayCapacity
     566             : 
     567      139296 :     const SUMOTime tau_jf_withLength = tauWithVehLength(myTau_jf, DEFAULT_VEH_LENGTH_WITH_GAP, 1.);
     568             :     // number of vehicles that fit into the NEXT queue (could be larger than expected with DEFAULT_VEH_LENGTH_WITH_GAP!)
     569      139296 :     const double headwayCapacity = MAX2(nextQueueSize, nextQueueCapacity / DEFAULT_VEH_LENGTH_WITH_GAP);
     570             :     // number of vehicles above which the NEXT queue is jammed
     571      139296 :     const double n_jam_threshold = headwayCapacity * nextJamThreshold / nextQueueCapacity;
     572             : 
     573             :     // slope a and axis offset b for the jam-jam headway function
     574             :     // solving f(x) = a * x + b
     575      139296 :     const double a = (STEPS2TIME(myTau_jj) * headwayCapacity - STEPS2TIME(tau_jf_withLength)) / (headwayCapacity - n_jam_threshold);
     576      139296 :     const double b = headwayCapacity * (STEPS2TIME(myTau_jj) - a);
     577             : 
     578             :     // it is only well defined for nextQueueSize >= n_jam_threshold (which may not be the case for longer vehicles), so we take the MAX
     579      139296 :     return TIME2STEPS(a * MAX2(nextQueueSize, n_jam_threshold) + b);
     580             : }
     581             : 
     582             : 
     583             : bool
     584     1419533 : MESegment::overtake() {
     585     1419557 :     return myOvertaking && RandHelper::rand() > (getBruttoOccupancy() / myCapacity);
     586             : }
     587             : 
     588             : 
     589             : void
     590    33796189 : MESegment::addReminders(MEVehicle* veh) const {
     591    33796189 :     if (veh->getQueIndex() != PARKING_QUEUE) {
     592    33795048 :         myQueues[veh->getQueIndex()].addReminders(veh);
     593             :     }
     594    33796189 : }
     595             : 
     596             : 
     597             : void
     598    33794101 : MESegment::receive(MEVehicle* veh, const int qIdx, SUMOTime time, const bool isDepart, const bool isTeleport, const bool newEdge) {
     599    33794101 :     const double speed = isDepart ? -1 : MAX2(veh->getSpeed(), MESO_MIN_SPEED); // on the previous segment
     600    33794101 :     veh->setSegment(this); // for arrival checking
     601             :     veh->setLastEntryTime(time);
     602             :     veh->setBlockTime(SUMOTime_MAX);
     603    33794101 :     if (!isDepart && (
     604             :                 // arrival on entering a new edge
     605     3662430 :                 (newEdge && veh->moveRoutePointer())
     606             :                 // arrival on entering a new segment
     607    32996291 :                 || veh->hasArrived())) {
     608             :         // route has ended
     609       15214 :         veh->setEventTime(time + TIME2STEPS(myLength / speed)); // for correct arrival speed
     610       15214 :         addReminders(veh);
     611       15214 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
     612       30324 :         veh->updateDetectors(time, true,
     613       15214 :                              veh->getEdge()->isVaporizing() ? MSMoveReminder::NOTIFICATION_VAPORIZED_VAPORIZER : MSMoveReminder::NOTIFICATION_ARRIVED);
     614       15214 :         MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
     615       15214 :         return;
     616             :     }
     617             :     assert(veh->getEdge() == &getEdge());
     618             :     // route continues
     619    33778887 :     Queue& q = myQueues[qIdx];
     620    33778887 :     const double maxSpeedOnEdge = veh->getEdge()->getLanes()[qIdx]->getVehicleMaxSpeed(veh);
     621             :     const double uspeed = MAX2(maxSpeedOnEdge, MESO_MIN_SPEED);
     622             :     std::vector<MEVehicle*>& cars = q.getModifiableVehicles();
     623             :     MEVehicle* newLeader = nullptr; // first vehicle in the current queue
     624    33778887 :     const SUMOTime stopTime = veh->checkStop(time);
     625    33778887 :     SUMOTime tleave = MAX2(stopTime + TIME2STEPS(myLength / uspeed) + getLinkPenalty(veh), q.getBlockTime());
     626    33778887 :     if (veh->isStopped()) {
     627        8327 :         myEdge.addWaiting(veh);
     628             :     }
     629    33778887 :     if (veh->isParking()) {
     630             :         veh->setEventTime(stopTime);
     631        1141 :         veh->setSegment(this, PARKING_QUEUE);
     632        1141 :         myEdge.getLanes()[0]->addParking(veh);  // TODO for GUI only
     633             :     } else {
     634    33777746 :         myEdge.lock();
     635    33777746 :         if (cars.empty()) {
     636    11673296 :             cars.push_back(veh);
     637    11673296 :             newLeader = veh;
     638             :         } else {
     639    22104450 :             SUMOTime leaderOut = cars[0]->getEventTime();
     640    22104450 :             if (!isDepart && leaderOut > tleave && overtake()) {
     641          20 :                 if (cars.size() == 1) {
     642           4 :                     MSGlobals::gMesoNet->removeLeaderCar(cars[0]);
     643             :                     newLeader = veh;
     644             :                 }
     645          20 :                 cars.insert(cars.begin() + 1, veh);
     646             :             } else {
     647    22104430 :                 tleave = MAX2(leaderOut + tauWithVehLength(myTau_ff, cars[0]->getVehicleType().getLengthWithGap(), cars[0]->getVehicleType().getCarFollowModel().getHeadwayTime()), tleave);
     648    22104430 :                 cars.insert(cars.begin(), veh);
     649             :             }
     650             :         }
     651    33777746 :         myEdge.unlock();
     652    33777746 :         myNumVehicles++;
     653    33777746 :         if (!isDepart && !isTeleport) {
     654             :             // departs and teleports could take place anywhere on the edge so they should not block regular flow
     655             :             // the -1 facilitates interleaving of multiple streams
     656    32979123 :             q.setEntryBlockTime(time + tauWithVehLength(myTau_ff, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime()) - 1);
     657             :         }
     658    33777746 :         q.setOccupancy(MIN2(myQueueCapacity, q.getOccupancy() + veh->getVehicleType().getLengthWithGap()));
     659             :         veh->setEventTime(tleave);
     660    33777746 :         veh->setSegment(this, qIdx);
     661             :     }
     662    33778887 :     addReminders(veh);
     663    33778887 :     if (isDepart) {
     664      797652 :         veh->onDepart();
     665      797652 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_DEPARTED);
     666    32981235 :     } else if (newEdge) {
     667     3662272 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
     668             :     } else {
     669    29318963 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_SEGMENT);
     670             :     }
     671    33778887 :     if (veh->isParking()) {
     672        1141 :         MSGlobals::gMesoNet->addLeaderCar(veh, nullptr);
     673             :     } else {
     674    33777746 :         if (newLeader != nullptr) {
     675    11673300 :             MSGlobals::gMesoNet->addLeaderCar(newLeader, getLink(newLeader));
     676             :         }
     677             :     }
     678             : }
     679             : 
     680             : 
     681             : bool
     682        8674 : MESegment::vaporizeAnyCar(SUMOTime currentTime, const MSDetectorFileOutput* filter) {
     683        9214 :     for (const Queue& q : myQueues) {
     684        8688 :         if (q.size() > 0) {
     685        8148 :             for (MEVehicle* const veh : q.getVehicles()) {
     686        8148 :                 if (filter->vehicleApplies(*veh)) {
     687        8148 :                     MSGlobals::gMesoNet->removeLeaderCar(veh);
     688        8148 :                     MSGlobals::gMesoNet->changeSegment(veh, currentTime + 1, &myVaporizationTarget, MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR);
     689             :                     return true;
     690             :                 }
     691             :             }
     692             :         }
     693             :     }
     694             :     return false;
     695             : }
     696             : 
     697             : 
     698             : void
     699         346 : MESegment::setSpeedForQueue(double newSpeed, SUMOTime currentTime, SUMOTime blockTime, const std::vector<MEVehicle*>& vehs) {
     700         346 :     MEVehicle* v = vehs.back();
     701         346 :     v->updateDetectors(currentTime, false);
     702         346 :     SUMOTime newEvent = MAX2(newArrival(v, newSpeed, currentTime), blockTime);
     703         346 :     if (v->getEventTime() != newEvent) {
     704         324 :         MSGlobals::gMesoNet->removeLeaderCar(v);
     705             :         v->setEventTime(newEvent);
     706         324 :         MSGlobals::gMesoNet->addLeaderCar(v, getLink(v));
     707             :     }
     708        1069 :     for (std::vector<MEVehicle*>::const_reverse_iterator i = vehs.rbegin() + 1; i != vehs.rend(); ++i) {
     709         723 :         (*i)->updateDetectors(currentTime, false);
     710         723 :         newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + myTau_ff);
     711             :         //newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + myTau_ff + (SUMOTime)((*(i - 1))->getVehicleType().getLength() / myTau_length));
     712         723 :         (*i)->setEventTime(newEvent);
     713             :     }
     714         346 : }
     715             : 
     716             : 
     717             : SUMOTime
     718        1069 : MESegment::newArrival(const MEVehicle* const v, double newSpeed, SUMOTime currentTime) {
     719             :     // since speed is only an upper bound pos may be to optimistic
     720        1069 :     const double pos = MIN2(myLength, STEPS2TIME(currentTime - v->getLastEntryTime()) * v->getSpeed());
     721             :     // traveltime may not be 0
     722        1069 :     double tt = (myLength - pos) / MAX2(newSpeed, MESO_MIN_SPEED);
     723        1069 :     return currentTime + MAX2(TIME2STEPS(tt), SUMOTime(1));
     724             : }
     725             : 
     726             : 
     727             : void
     728         971 : MESegment::setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh, int qIdx) {
     729         971 :     recomputeJamThreshold(jamThresh);
     730             :     //myTau_length = MAX2(MESO_MIN_SPEED, newSpeed) * myEdge.getLanes().size() / TIME2STEPS(1);
     731             :     int i = 0;
     732        2024 :     for (const Queue& q : myQueues) {
     733        1053 :         if (q.size() != 0) {
     734         379 :             if (qIdx == -1 || qIdx == i) {
     735         346 :                 setSpeedForQueue(newSpeed, currentTime, q.getBlockTime(), q.getVehicles());
     736             :             }
     737             :         }
     738        1053 :         i++;
     739             :     }
     740         971 : }
     741             : 
     742             : 
     743             : SUMOTime
     744     1185634 : MESegment::getEventTime() const {
     745             :     SUMOTime result = SUMOTime_MAX;
     746     2655719 :     for (const Queue& q : myQueues) {
     747     1470085 :         if (q.size() != 0 && q.getVehicles().back()->getEventTime() < result) {
     748             :             result = q.getVehicles().back()->getEventTime();
     749             :         }
     750             :     }
     751     1185634 :     if (result < SUMOTime_MAX) {
     752      948165 :         return result;
     753             :     }
     754             :     return -1;
     755             : }
     756             : 
     757             : 
     758             : void
     759        5009 : MESegment::saveState(OutputDevice& out) const {
     760             :     bool write = false;
     761        9751 :     for (const Queue& q : myQueues) {
     762        5048 :         if (q.getBlockTime() != -1 || !q.getVehicles().empty()) {
     763             :             write = true;
     764             :             break;
     765             :         }
     766             :     }
     767        5009 :     if (write) {
     768         612 :         out.openTag(SUMO_TAG_SEGMENT).writeAttr(SUMO_ATTR_ID, getID());
     769         623 :         for (const Queue& q : myQueues) {
     770         634 :             out.openTag(SUMO_TAG_VIEWSETTINGS_VEHICLES).writeAttr(SUMO_ATTR_TIME, toString<SUMOTime>(q.getBlockTime()));
     771             :             out.writeAttr(SUMO_ATTR_VALUE, q.getVehicles());
     772         634 :             out.closeTag();
     773             :         }
     774         612 :         out.closeTag();
     775             :     }
     776        5009 : }
     777             : 
     778             : 
     779             : void
     780          29 : MESegment::clearState() {
     781          58 :     for (Queue& q : myQueues) {
     782             :         q.getModifiableVehicles().clear();
     783             :     }
     784          29 : }
     785             : 
     786             : void
     787         216 : MESegment::loadState(const std::vector<std::string>& vehIds, MSVehicleControl& vc, const SUMOTime block, const int queIdx) {
     788         216 :     Queue& q = myQueues[queIdx];
     789         431 :     for (const std::string& id : vehIds) {
     790         215 :         MEVehicle* v = static_cast<MEVehicle*>(vc.getVehicle(id));
     791             :         // vehicle could be removed due to options
     792         215 :         if (v != nullptr) {
     793             :             assert(v->getSegment() == this);
     794         213 :             q.getModifiableVehicles().push_back(v);
     795         213 :             myNumVehicles++;
     796         213 :             q.setOccupancy(q.getOccupancy() + v->getVehicleType().getLengthWithGap());
     797             :         }
     798             :     }
     799         216 :     if (q.size() != 0) {
     800             :         // add the last vehicle of this queue
     801             :         // !!! one question - what about the previously added vehicle? Is it stored twice?
     802          98 :         MEVehicle* veh = q.getVehicles().back();
     803          98 :         MSGlobals::gMesoNet->addLeaderCar(veh, getLink(veh));
     804             :     }
     805             :     q.setBlockTime(block);
     806         216 :     q.setOccupancy(MIN2(q.getOccupancy(), myQueueCapacity));
     807         216 : }
     808             : 
     809             : 
     810             : std::vector<const MEVehicle*>
     811          80 : MESegment::getVehicles() const {
     812             :     std::vector<const MEVehicle*> result;
     813         180 :     for (const Queue& q : myQueues) {
     814         100 :         result.insert(result.end(), q.getVehicles().begin(), q.getVehicles().end());
     815             :     }
     816          80 :     return result;
     817             : }
     818             : 
     819             : 
     820             : bool
     821     3688019 : MESegment::hasBlockedLeader() const {
     822     7435649 :     for (const Queue& q : myQueues) {
     823     3758891 :         if (q.size() > 0 && q.getVehicles().back()->getWaitingTime() > 0) {
     824             :             return true;
     825             :         }
     826             :     }
     827             :     return false;
     828             : }
     829             : 
     830             : 
     831             : double
     832           0 : MESegment::getFlow() const {
     833           0 :     return 3600 * getCarNumber() * getMeanSpeed() / myLength;
     834             : }
     835             : 
     836             : 
     837             : SUMOTime
     838    33778887 : MESegment::getLinkPenalty(const MEVehicle* veh) const {
     839    67504332 :     const MSLink* link = getLink(veh, myTLSPenalty || myCheckMinorPenalty);
     840    33778887 :     if (link != nullptr) {
     841             :         SUMOTime result = 0;
     842     1546335 :         if (link->isTLSControlled()) {
     843             :             result += link->getMesoTLSPenalty();
     844             :         }
     845             :         // minor tls links may get an additional penalty
     846      448432 :         if (!link->havePriority() &&
     847             :                 // do not apply penalty on top of tLSPenalty
     848     1546335 :                 !myTLSPenalty &&
     849             :                 // do not apply penalty if limited control is active
     850      413156 :                 (!MSGlobals::gMesoLimitedJunctionControl || limitedControlOverride(link))) {
     851      410686 :             result += myMinorPenalty;
     852             :         }
     853     1546335 :         return result;
     854             :     } else {
     855             :         return 0;
     856             :     }
     857             : }
     858             : 
     859             : 
     860             : double
     861           3 : MESegment::getWaitingSeconds() const {
     862             :     double result = 0;
     863           6 :     for (const Queue& q : myQueues) {
     864             :         // @note: only the leader currently accumulates waitingTime but this might change in the future
     865           4 :         for (const MEVehicle* veh : q.getVehicles()) {
     866           1 :             result += veh->getWaitingSeconds();
     867             :         }
     868             :     }
     869           3 :     return result;
     870             : }
     871             : 
     872             : 
     873             : /****************************************************************************/

Generated by: LCOV version 1.14