LCOV - code coverage report
Current view: top level - src/mesosim - MESegment.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 99.2 % 366 363
Test Date: 2024-11-20 15:55:46 Functions: 97.4 % 38 37

            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     23770312 : MESegment::Queue::remove(MEVehicle* v) {
      68     23770312 :     myOccupancy -= v->getVehicleType().getLengthWithGap();
      69              :     assert(std::find(myVehicles.begin(), myVehicles.end(), v) != myVehicles.end());
      70     23770312 :     if (v == myVehicles.back()) {
      71              :         myVehicles.pop_back();
      72     23764033 :         if (myVehicles.empty()) {
      73      6261913 :             myOccupancy = 0.;
      74              :         } else {
      75     17502120 :             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       122121 : MESegment::Queue::addDetector(MSMoveReminder* data) {
      85       122121 :     myDetectorData.push_back(data);
      86       127833 :     for (MEVehicle* const v : myVehicles) {
      87         5712 :         v->addReminder(data);
      88              :     }
      89       122121 : }
      90              : 
      91              : void
      92     23807575 : MESegment::Queue::addReminders(MEVehicle* veh) const {
      93     33138922 :     for (MSMoveReminder* rem : myDetectorData) {
      94      9331347 :         veh->addReminder(rem);
      95              :     }
      96     23807575 : }
      97              : 
      98              : // ===========================================================================
      99              : // MESegment method definitions
     100              : // ===========================================================================
     101       562854 : 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       562854 :                      const MesoEdgeType& edgeType):
     107       562854 :     Named(id), myEdge(parent), myNextSegment(next),
     108       562854 :     myLength(length), myIndex(idx),
     109       562854 :     myTau_length(TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, speed)),
     110       562854 :     myNumVehicles(0),
     111       562854 :     myLastHeadway(TIME2STEPS(-1)),
     112       562854 :     myMeanSpeed(speed),
     113      1125417 :     myLastMeanSpeedUpdate(SUMOTime_MIN) {
     114              : 
     115              :     const std::vector<MSLane*>& lanes = parent.getLanes();
     116              :     int usableLanes = 0;
     117      1221633 :     for (MSLane* const l : lanes) {
     118       658779 :         const SVCPermissions allow = MSEdge::getMesoPermissions(l->getPermissions());
     119       658779 :         if (multiQueue) {
     120        64742 :             myQueues.push_back(Queue(allow));
     121              :         }
     122       658779 :         if (allow != 0) {
     123       630495 :             usableLanes++;
     124              :         }
     125              :     }
     126       562854 :     if (usableLanes == 0) {
     127              :         // cars won't drive here. Give sensible tau values capacity for the ignored classes
     128              :         usableLanes = 1;
     129              :     }
     130       562854 :     if (multiQueue) {
     131        14480 :         if (next == nullptr) {
     132        60506 :             for (const MSEdge* const edge : parent.getSuccessors()) {
     133        46370 :                 const std::vector<MSLane*>* const allowed = parent.allowedLanes(*edge);
     134              :                 assert(allowed != nullptr);
     135              :                 assert(allowed->size() > 0);
     136        99059 :                 for (MSLane* const l : *allowed) {
     137        52689 :                     std::vector<MSLane*>::const_iterator it = std::find(lanes.begin(), lanes.end(), l);
     138        52689 :                     myFollowerMap[edge] |= (1 << distance(lanes.begin(), it));
     139              :                 }
     140              :             }
     141              :         }
     142        14480 :         myQueueCapacity = length;
     143              :     } else {
     144      1096748 :         myQueues.push_back(Queue(parent.getPermissions()));
     145              :     }
     146              : 
     147       562854 :     initSegment(edgeType, parent, length * usableLanes);
     148       562854 : }
     149              : 
     150              : void
     151       563094 : MESegment::initSegment(const MesoEdgeType& edgeType, const MSEdge& parent, const double capacity) {
     152              : 
     153       563094 :     myCapacity = capacity;
     154       563094 :     if (myQueues.size() == 1) {
     155       549002 :         const double laneScale = capacity / myLength;
     156       549002 :         myQueueCapacity = capacity;
     157       549002 :         myTau_length = TIME2STEPS(1) / MAX2(MESO_MIN_SPEED, myMeanSpeed) / laneScale;
     158              :         // Eissfeldt p. 90 and 151 ff.
     159       549002 :         myTau_ff = (SUMOTime)((double)edgeType.tauff / laneScale);
     160       549002 :         myTau_fj = (SUMOTime)((double)edgeType.taufj / laneScale);
     161       549002 :         myTau_jf = (SUMOTime)((double)edgeType.taujf / laneScale);
     162       549002 :         myTau_jj = (SUMOTime)((double)edgeType.taujj / laneScale);
     163              :     } else {
     164        14092 :         myTau_ff = edgeType.tauff;
     165        14092 :         myTau_fj = edgeType.taufj;
     166        14092 :         myTau_jf = edgeType.taujf;
     167        14092 :         myTau_jj = edgeType.taujj;
     168              :     }
     169              : 
     170       563094 :     myJunctionControl = myNextSegment == nullptr && (edgeType.junctionControl || MELoop::isEnteringRoundabout(parent));
     171       562446 :     myTLSPenalty = ((edgeType.tlsPenalty > 0 || edgeType.tlsFlowPenalty > 0) &&
     172              :                     // only apply to the last segment of a tls-controlled edge
     173       563370 :                     myNextSegment == nullptr && (
     174          206 :                         parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT ||
     175          206 :                         parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION ||
     176              :                         parent.getToJunction()->getType() == SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED));
     177              : 
     178              :     // only apply to the last segment of an uncontrolled edge that has at least 1 minor link
     179      1126508 :     myCheckMinorPenalty = (edgeType.minorPenalty > 0 &&
     180          320 :                            myNextSegment == nullptr &&
     181              :                            parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT &&
     182              :                            parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_NOJUNCTION &&
     183       563272 :                            parent.getToJunction()->getType() != SumoXMLNodeType::TRAFFIC_LIGHT_RIGHT_ON_RED &&
     184          178 :                            parent.hasMinorLink());
     185       563094 :     myMinorPenalty = edgeType.minorPenalty;
     186       563094 :     myOvertaking = edgeType.overtaking && myCapacity > myLength;
     187              : 
     188              :     //std::cout << getID() << " myMinorPenalty=" << myMinorPenalty << " myTLSPenalty=" << myTLSPenalty << " myJunctionControl=" << myJunctionControl << " myOvertaking=" << myOvertaking << "\n";
     189              : 
     190       563094 :     recomputeJamThreshold(edgeType.jamThreshold);
     191       563094 : }
     192              : 
     193        43383 : MESegment::MESegment(const std::string& id):
     194              :     Named(id),
     195        43383 :     myEdge(myDummyParent), // arbitrary edge needed to supply the needed reference
     196        43383 :     myNextSegment(nullptr), myLength(0), myIndex(0),
     197        43383 :     myTau_ff(0), myTau_fj(0), myTau_jf(0), myTau_jj(0),
     198        43383 :     myTLSPenalty(false),
     199        43383 :     myCheckMinorPenalty(false),
     200        43383 :     myMinorPenalty(0),
     201        43383 :     myJunctionControl(false),
     202        43383 :     myOvertaking(false),
     203        43383 :     myTau_length(1) {
     204        43383 : }
     205              : 
     206              : 
     207              : void
     208         1128 : MESegment::updatePermissions() {
     209         1128 :     if (myQueues.size() > 1) {
     210           64 :         for (MSLane* lane : myEdge.getLanes()) {
     211           48 :             myQueues[lane->getIndex()].setPermissions(lane->getPermissions());
     212              :         }
     213              :     } else {
     214         1112 :         myQueues.back().setPermissions(myEdge.getPermissions());
     215              :     }
     216         1128 : }
     217              : 
     218              : 
     219              : void
     220       564065 : MESegment::recomputeJamThreshold(double jamThresh) {
     221       564065 :     if (jamThresh == DO_NOT_PATCH_JAM_THRESHOLD) {
     222              :         return;
     223              :     }
     224       564065 :     if (jamThresh < 0) {
     225              :         // compute based on speed
     226       564061 :         myJamThreshold = jamThresholdForSpeed(myEdge.getSpeedLimit(), jamThresh);
     227              :     } else {
     228              :         // compute based on specified percentage
     229            4 :         myJamThreshold = jamThresh * myCapacity;
     230              :     }
     231              : }
     232              : 
     233              : 
     234              : double
     235      3943596 : MESegment::jamThresholdForSpeed(double speed, double jamThresh) const {
     236              :     // vehicles driving freely at maximum speed should not jam
     237              :     // we compute how many vehicles could possible enter the segment until the first vehicle leaves
     238              :     // and multiply by the space these vehicles would occupy
     239              :     // the jamThresh parameter is scale the resulting value
     240      3943596 :     if (speed == 0) {
     241              :         return std::numeric_limits<double>::max();  // never jam. Irrelevant at speed 0 anyway
     242              :     }
     243              : #ifdef DEBUG_JAMTHRESHOLD
     244              :     if (true || DEBUG_COND) {
     245              :         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
     246              :                   << "\n";
     247              :     }
     248              : #endif
     249      3943375 :     return std::ceil(myLength / (-jamThresh * speed * STEPS2TIME(tauWithVehLength(myTau_ff, DEFAULT_VEH_LENGTH_WITH_GAP, 1.)))) * DEFAULT_VEH_LENGTH_WITH_GAP;
     250              : }
     251              : 
     252              : 
     253              : void
     254       120511 : MESegment::addDetector(MSMoveReminder* data, int queueIndex) {
     255       120511 :     if (queueIndex == -1) {
     256       238764 :         for (Queue& q : myQueues) {
     257       120187 :             q.addDetector(data);
     258              :         }
     259              :     } else {
     260              :         assert(queueIndex < (int)myQueues.size());
     261         1934 :         myQueues[queueIndex].addDetector(data);
     262              :     }
     263       120511 : }
     264              : 
     265              : 
     266              : /*
     267              : void
     268              : MESegment::removeDetector(MSMoveReminder* data) {
     269              :     std::vector<MSMoveReminder*>::iterator it = std::find(myDetectorData.begin(), myDetectorData.end(), data);
     270              :     if (it != myDetectorData.end()) {
     271              :         myDetectorData.erase(it);
     272              :     }
     273              :     for (const Queue& q : myQueues) {
     274              :         for (MEVehicle* const v : q.getVehicles()) {
     275              :             v->removeReminder(data);
     276              :         }
     277              :     }
     278              : }
     279              : */
     280              : 
     281              : 
     282              : void
     283      6380864 : MESegment::prepareDetectorForWriting(MSMoveReminder& data, int queueIndex) {
     284      6380864 :     const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
     285      6380864 :     if (queueIndex == -1) {
     286     12833364 :         for (const Queue& q : myQueues) {
     287              :             SUMOTime earliestExitTime = currentTime;
     288      7827398 :             for (std::vector<MEVehicle*>::const_reverse_iterator i = q.getVehicles().rbegin(); i != q.getVehicles().rend(); ++i) {
     289      1374298 :                 const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
     290      1374298 :                 (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
     291      1374298 :                 earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
     292              :             }
     293              :         }
     294              :     } else {
     295              :         SUMOTime earliestExitTime = currentTime;
     296          612 :         for (std::vector<MEVehicle*>::const_reverse_iterator i = myQueues[queueIndex].getVehicles().rbegin(); i != myQueues[queueIndex].getVehicles().rend(); ++i) {
     297           12 :             const SUMOTime exitTime = MAX2(earliestExitTime, (*i)->getEventTime());
     298           12 :             (*i)->updateDetectorForWriting(&data, currentTime, exitTime);
     299           12 :             earliestExitTime = exitTime + tauWithVehLength(myTau_ff, (*i)->getVehicleType().getLengthWithGap(), (*i)->getVehicleType().getCarFollowModel().getHeadwayTime());
     300              :         }
     301              :     }
     302      6380864 : }
     303              : 
     304              : 
     305              : SUMOTime
     306     61047410 : MESegment::hasSpaceFor(const MEVehicle* const veh, const SUMOTime entryTime, int& qIdx, const bool init) const {
     307              :     SUMOTime earliestEntry = SUMOTime_MAX;
     308     61047410 :     qIdx = 0;
     309     61047410 :     if (myNumVehicles == 0 && myQueues.size() == 1) {
     310              :         // we have always space for at least one vehicle
     311     14935909 :         if (myQueues.front().allows(veh->getVClass())) {
     312              :             return entryTime;
     313              :         }  else {
     314              :             return earliestEntry;
     315              :         }
     316              :     }
     317     46111501 :     const SUMOVehicleClass svc = veh->getVClass();
     318              :     int minSize = std::numeric_limits<int>::max();
     319     46111501 :     const MSEdge* const succ = myNextSegment == nullptr ? veh->succEdge(1) : nullptr;
     320     93727113 :     for (int i = 0; i < (int)myQueues.size(); i++) {
     321     47615612 :         const Queue& q = myQueues[i];
     322     47615612 :         const double newOccupancy = q.size() == 0 ? 0. : q.getOccupancy() + veh->getVehicleType().getLengthWithGap();
     323     47615612 :         if (newOccupancy <= myQueueCapacity) { // we must ensure that occupancy remains below capacity
     324     26972408 :             if (succ == nullptr || myFollowerMap.count(succ) == 0 || ((myFollowerMap.find(succ)->second & (1 << i)) != 0)) {
     325     25191026 :                 if (q.allows(svc) && q.size() < minSize) {
     326     24722026 :                     if (init) {
     327              :                         // regular insertions and initial insertions must respect different constraints:
     328              :                         // - regular insertions must respect entryBlockTime
     329              :                         // - initial insertions should not cause additional jamming
     330              :                         // - inserted vehicle should be able to continue at the current speed
     331      6949492 :                         if (q.getOccupancy() <= myJamThreshold && !hasBlockedLeader() && !myTLSPenalty) {
     332      3569957 :                             if (newOccupancy <= myJamThreshold) {
     333      1219975 :                                 qIdx = i;
     334              :                                 minSize = q.size();
     335              :                             }
     336              :                         } else {
     337      3379535 :                             if (newOccupancy <= jamThresholdForSpeed(getMeanSpeed(false), -1)) {
     338      2616525 :                                 qIdx = i;
     339              :                                 minSize = q.size();
     340              :                             }
     341              :                         }
     342     17772534 :                     } else if (entryTime >= q.getEntryBlockTime()) {
     343     17477965 :                         qIdx = i;
     344              :                         minSize = q.size();
     345              :                     } else {
     346              :                         earliestEntry = MIN2(earliestEntry, q.getEntryBlockTime());
     347              :                     }
     348              :                 }
     349              :             }
     350              :         }
     351              :     }
     352     46111501 :     if (minSize == std::numeric_limits<int>::max()) {
     353              :         return earliestEntry;
     354              :     }
     355              :     return entryTime;
     356              : }
     357              : 
     358              : 
     359              : bool
     360      1965903 : MESegment::initialise(MEVehicle* veh, SUMOTime time) {
     361      1965903 :     int qIdx = 0;
     362      1965903 :     if (hasSpaceFor(veh, time, qIdx, true) == time) {
     363       677568 :         receive(veh, qIdx, time, true);
     364              :         // we can check only after insertion because insertion may change the route via devices
     365              :         std::string msg;
     366      1354482 :         if (MSGlobals::gCheckRoutes && !veh->hasValidRoute(msg)) {
     367            4 :             throw ProcessError("Vehicle '" + veh->getID() + "' has no valid route. " + msg);
     368              :         }
     369              :         return true;
     370              :     }
     371              :     return false;
     372              : }
     373              : 
     374              : 
     375              : double
     376     26858148 : MESegment::getMeanSpeed(bool useCached) const {
     377     26858148 :     const SUMOTime currentTime = MSNet::getInstance()->getCurrentTimeStep();
     378     26858148 :     if (currentTime != myLastMeanSpeedUpdate || !useCached) {
     379     26765652 :         myLastMeanSpeedUpdate = currentTime;
     380              :         double v = 0;
     381              :         int count = 0;
     382     53877551 :         for (const Queue& q : myQueues) {
     383     27111899 :             const SUMOTime tau = q.getOccupancy() < myJamThreshold ? myTau_ff : myTau_jf;
     384     27111899 :             SUMOTime earliestExitTime = currentTime;
     385     27111899 :             count += q.size();
     386    131913974 :             for (std::vector<MEVehicle*>::const_reverse_iterator veh = q.getVehicles().rbegin(); veh != q.getVehicles().rend(); ++veh) {
     387    104802075 :                 v += (*veh)->getConservativeSpeed(earliestExitTime); // earliestExitTime is updated!
     388    104802075 :                 earliestExitTime += tauWithVehLength(tau, (*veh)->getVehicleType().getLengthWithGap(), (*veh)->getVehicleType().getCarFollowModel().getHeadwayTime());
     389              :             }
     390              :         }
     391     26765652 :         if (count == 0) {
     392           18 :             myMeanSpeed = myEdge.getSpeedLimit();
     393              :         } else {
     394     26765634 :             myMeanSpeed = v / (double) count;
     395              :         }
     396              :     }
     397     26858148 :     return myMeanSpeed;
     398              : }
     399              : 
     400              : 
     401              : void
     402       206604 : MESegment::writeVehicles(OutputDevice& of) const {
     403       413626 :     for (const Queue& q : myQueues) {
     404       221272 :         for (const MEVehicle* const veh : q.getVehicles()) {
     405        14250 :             MSXMLRawOut::writeVehicle(of, *veh);
     406              :         }
     407              :     }
     408       206604 : }
     409              : 
     410              : 
     411              : MEVehicle*
     412     23770312 : MESegment::removeCar(MEVehicle* v, SUMOTime leaveTime, const MSMoveReminder::Notification reason) {
     413     23770312 :     Queue& q = myQueues[v->getQueIndex()];
     414              :     // One could be tempted to do  v->setSegment(next); here but position on lane will be invalid if next == 0
     415     23770312 :     v->updateDetectors(leaveTime, true, reason);
     416     23770312 :     myNumVehicles--;
     417     23770312 :     myEdge.lock();
     418     23770312 :     MEVehicle* nextLeader = q.remove(v);
     419     23770312 :     myEdge.unlock();
     420     23770312 :     return nextLeader;
     421              : }
     422              : 
     423              : 
     424              : SUMOTime
     425        13548 : MESegment::getNextInsertionTime(SUMOTime earliestEntry) const {
     426              :     // since we do not know which queue will be used we give a conservative estimate
     427              :     SUMOTime earliestLeave = earliestEntry;
     428              :     SUMOTime latestEntry = -1;
     429        27354 :     for (const Queue& q : myQueues) {
     430              :         earliestLeave = MAX2(earliestLeave, q.getBlockTime());
     431              :         latestEntry = MAX2(latestEntry, q.getEntryBlockTime());
     432              :     }
     433        13548 :     if (myEdge.getSpeedLimit() == 0) {
     434           12 :         return MAX2(earliestEntry, latestEntry);    // FIXME: This line is just an adhoc-fix to avoid division by zero (Leo)
     435              :     } else {
     436        13536 :         return MAX3(earliestEntry, earliestLeave - TIME2STEPS(myLength / myEdge.getSpeedLimit()), latestEntry);
     437              :     }
     438              : }
     439              : 
     440              : 
     441              : MSLink*
     442    113213468 : MESegment::getLink(const MEVehicle* veh, bool penalty) const {
     443    113213468 :     if (myJunctionControl || penalty) {
     444     23010617 :         const MSEdge* const nextEdge = veh->succEdge(1);
     445     23010617 :         if (nextEdge == nullptr || veh->getQueIndex() == PARKING_QUEUE) {
     446              :             return nullptr;
     447              :         }
     448              :         // try to find any link leading to our next edge, start with the lane pointed to by the que index
     449     22093035 :         const MSLane* const bestLane = myEdge.getLanes()[veh->getQueIndex()];
     450     25067837 :         for (MSLink* const link : bestLane->getLinkCont()) {
     451     24595719 :             if (&link->getLane()->getEdge() == nextEdge) {
     452              :                 return link;
     453              :             }
     454              :         }
     455              :         // this is for the non-multique case, maybe we should use caching here !!!
     456      1006870 :         for (const MSLane* const lane : myEdge.getLanes()) {
     457      1006770 :             if (lane != bestLane) {
     458       785063 :                 for (MSLink* const link : lane->getLinkCont()) {
     459       664227 :                     if (&link->getLane()->getEdge() == nextEdge) {
     460              :                         return link;
     461              :                     }
     462              :                 }
     463              :             }
     464              :         }
     465              :     }
     466              :     return nullptr;
     467              : }
     468              : 
     469              : 
     470              : bool
     471     31532328 : MESegment::isOpen(const MEVehicle* veh) const {
     472              : #ifdef DEBUG_OPENED
     473              :     if (DEBUG_COND || DEBUG_COND2(veh)) {
     474              :         gDebugFlag1 = true;
     475              :         std::cout << SIMTIME << " opened seg=" << getID() << " veh=" << Named::getIDSecure(veh)
     476              :                   << " tlsPenalty=" << myTLSPenalty;
     477              :         const MSLink* link = getLink(veh);
     478              :         if (link == 0) {
     479              :             std::cout << " link=0";
     480              :         } else {
     481              :             std::cout << " prio=" << link->havePriority()
     482              :                       << " override=" << limitedControlOverride(link)
     483              :                       << " isOpen=" << link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
     484              :                                                     veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
     485              :                                                     veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime(),
     486              :                                                     0, nullptr, false, veh)
     487              :                       << " et=" << veh->getEventTime()
     488              :                       << " v=" << veh->getSpeed()
     489              :                       << " vLeave=" << veh->estimateLeaveSpeed(link)
     490              :                       << " impatience=" << veh->getImpatience()
     491              :                       << " tWait=" << veh->getWaitingTime();
     492              :         }
     493              :         std::cout << "\n";
     494              :         gDebugFlag1 = false;
     495              :     }
     496              : #endif
     497     31532328 :     if (myTLSPenalty) {
     498              :         // XXX should limited control take precedence over tls penalty?
     499              :         return true;
     500              :     }
     501     31483508 :     const MSLink* link = getLink(veh);
     502              :     return (link == nullptr
     503      9471465 :             || link->havePriority()
     504      8659672 :             || limitedControlOverride(link)
     505     40142416 :             || link->opened(veh->getEventTime(), veh->getSpeed(), veh->estimateLeaveSpeed(link),
     506      8658908 :                             veh->getVehicleType().getLengthWithGap(), veh->getImpatience(),
     507      8658908 :                             veh->getVehicleType().getCarFollowModel().getMaxDecel(), veh->getWaitingTime(),
     508              :                             0, nullptr, false, veh));
     509              : }
     510              : 
     511              : 
     512              : bool
     513      8662862 : MESegment::limitedControlOverride(const MSLink* link) const {
     514              :     assert(link != nullptr);
     515      8662862 :     if (!MSGlobals::gMesoLimitedJunctionControl) {
     516              :         return false;
     517              :     }
     518              :     // if the target segment of this link is not saturated junction control is disabled
     519              :     const MSEdge& targetEdge = link->getLane()->getEdge();
     520         8248 :     const MESegment* target = MSGlobals::gMesoNet->getSegmentForEdge(targetEdge);
     521         8248 :     return (target->getBruttoOccupancy() * 2 < target->myJamThreshold) && !targetEdge.isRoundabout();
     522              : }
     523              : 
     524              : 
     525              : void
     526     23770312 : MESegment::send(MEVehicle* veh, MESegment* const next, const int nextQIdx, SUMOTime time, const MSMoveReminder::Notification reason) {
     527     23770312 :     Queue& q = myQueues[veh->getQueIndex()];
     528              :     assert(isInvalid(next) || time >= q.getBlockTime());
     529     23770312 :     MSLink* const link = getLink(veh);
     530     23770312 :     if (link != nullptr) {
     531      1069669 :         link->removeApproaching(veh);
     532              :     }
     533     23770312 :     if (veh->isStopped()) {
     534         7320 :         veh->processStop();
     535              :     }
     536     23770312 :     MEVehicle* lc = removeCar(veh, time, reason); // new leaderCar
     537              :     q.setBlockTime(time);
     538              :     if (!isInvalid(next)) {
     539     23127490 :         const bool nextFree = next->myQueues[nextQIdx].getOccupancy() <= next->myJamThreshold;
     540     23127490 :         const SUMOTime tau = (q.getOccupancy() <= myJamThreshold
     541     23127490 :                               ? (nextFree ? myTau_ff : myTau_fj)
     542       402668 :                               : (nextFree ? myTau_jf : getTauJJ((double)next->myQueues[nextQIdx].size(), next->myQueueCapacity, next->myJamThreshold)));
     543              :         assert(tau >= 0);
     544     23127490 :         myLastHeadway = tauWithVehLength(tau, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime());
     545     23127490 :         if (myTLSPenalty) {
     546        48820 :             const MSLink* const tllink = getLink(veh, true);
     547        48820 :             if (tllink != nullptr && tllink->isTLSControlled()) {
     548              :                 assert(tllink->getGreenFraction() > 0);
     549        48820 :                 myLastHeadway = (SUMOTime)((double)myLastHeadway / tllink->getGreenFraction());
     550              :             }
     551              :         }
     552     23127490 :         q.setBlockTime(q.getBlockTime() + myLastHeadway);
     553              :     }
     554     23770312 :     if (lc != nullptr) {
     555              :         lc->setEventTime(MAX2(lc->getEventTime(), q.getBlockTime()));
     556     17502120 :         MSGlobals::gMesoNet->addLeaderCar(lc, getLink(lc));
     557              :     }
     558     23770312 : }
     559              : 
     560              : SUMOTime
     561       135148 : MESegment::getTauJJ(double nextQueueSize, double nextQueueCapacity, double nextJamThreshold) const {
     562              :     // compute coefficients for the jam-jam headway function
     563              :     // this function models the effect that "empty space" needs to move
     564              :     // backwards through the downstream segment before the upstream segment may
     565              :     // send annother vehicle.
     566              :     // this allows jams to clear and move upstream.
     567              :     // the headway function f(x) depends on the number of vehicles in the
     568              :     // downstream segment x
     569              :     // f is a linear function that passes through the following fixed points:
     570              :     // f(n_jam_threshold) = tau_jf_withLength (for continuity)
     571              :     // f(headwayCapacity) = myTau_jj * headwayCapacity
     572              : 
     573       135148 :     const SUMOTime tau_jf_withLength = tauWithVehLength(myTau_jf, DEFAULT_VEH_LENGTH_WITH_GAP, 1.);
     574              :     // number of vehicles that fit into the NEXT queue (could be larger than expected with DEFAULT_VEH_LENGTH_WITH_GAP!)
     575       135148 :     const double headwayCapacity = MAX2(nextQueueSize, nextQueueCapacity / DEFAULT_VEH_LENGTH_WITH_GAP);
     576              :     // number of vehicles above which the NEXT queue is jammed
     577       135148 :     const double n_jam_threshold = headwayCapacity * nextJamThreshold / nextQueueCapacity;
     578              : 
     579              :     // slope a and axis offset b for the jam-jam headway function
     580              :     // solving f(x) = a * x + b
     581       135148 :     const double a = (STEPS2TIME(myTau_jj) * headwayCapacity - STEPS2TIME(tau_jf_withLength)) / (headwayCapacity - n_jam_threshold);
     582       135148 :     const double b = headwayCapacity * (STEPS2TIME(myTau_jj) - a);
     583              : 
     584              :     // it is only well defined for nextQueueSize >= n_jam_threshold (which may not be the case for longer vehicles), so we take the MAX
     585       135148 :     return TIME2STEPS(a * MAX2(nextQueueSize, n_jam_threshold) + b);
     586              : }
     587              : 
     588              : 
     589              : bool
     590      1146736 : MESegment::overtake() {
     591      1146760 :     return myOvertaking && RandHelper::rand() > (getBruttoOccupancy() / myCapacity);
     592              : }
     593              : 
     594              : 
     595              : void
     596     23808907 : MESegment::addReminders(MEVehicle* veh) const {
     597     23808907 :     if (veh->getQueIndex() != PARKING_QUEUE) {
     598     23807575 :         myQueues[veh->getQueIndex()].addReminders(veh);
     599              :     }
     600     23808907 : }
     601              : 
     602              : 
     603              : void
     604     23806816 : MESegment::receive(MEVehicle* veh, const int qIdx, SUMOTime time, const bool isDepart, const bool isTeleport, const bool newEdge) {
     605     23806816 :     const double speed = isDepart ? -1 : MAX2(veh->getSpeed(), MESO_MIN_SPEED); // on the previous segment
     606     23806816 :     veh->setSegment(this); // for arrival checking
     607              :     veh->setLastEntryTime(time);
     608              :     veh->setBlockTime(SUMOTime_MAX);
     609     23806816 :     if (!isDepart && (
     610              :                 // arrival on entering a new edge
     611      2754544 :                 (newEdge && veh->moveRoutePointer())
     612              :                 // arrival on entering a new segment
     613     23129090 :                 || veh->hasArrived())) {
     614              :         // route has ended
     615        15234 :         veh->setEventTime(time + TIME2STEPS(myLength / speed)); // for correct arrival speed
     616        15234 :         addReminders(veh);
     617        15234 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
     618        30364 :         veh->updateDetectors(time, true,
     619        15234 :                              veh->getEdge()->isVaporizing() ? MSMoveReminder::NOTIFICATION_VAPORIZED_VAPORIZER : MSMoveReminder::NOTIFICATION_ARRIVED);
     620        15234 :         MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
     621        15234 :         return;
     622              :     }
     623              :     assert(veh->getEdge() == &getEdge());
     624              :     // route continues
     625     23791582 :     Queue& q = myQueues[qIdx];
     626     23791582 :     const double maxSpeedOnEdge = veh->getEdge()->getLanes()[qIdx]->getVehicleMaxSpeed(veh);
     627              :     const double uspeed = MAX2(maxSpeedOnEdge, MESO_MIN_SPEED);
     628              :     std::vector<MEVehicle*>& cars = q.getModifiableVehicles();
     629              :     MEVehicle* newLeader = nullptr; // first vehicle in the current queue
     630     23791582 :     const SUMOTime stopTime = veh->checkStop(time);
     631     23791582 :     SUMOTime tleave = MAX2(stopTime + TIME2STEPS(myLength / uspeed) + getLinkPenalty(veh), q.getBlockTime());
     632     23791582 :     if (veh->isStopped()) {
     633         8965 :         myEdge.addWaiting(veh);
     634              :     }
     635     23791582 :     if (veh->isParking()) {
     636              :         veh->setEventTime(stopTime);
     637         1332 :         veh->setSegment(this, PARKING_QUEUE);
     638         1332 :         myEdge.getLanes()[0]->addParking(veh);  // TODO for GUI only
     639              :     } else {
     640     23790250 :         myEdge.lock();
     641     23790250 :         if (cars.empty()) {
     642      6266824 :             cars.push_back(veh);
     643              :             newLeader = veh;
     644              :         } else {
     645     17523426 :             SUMOTime leaderOut = cars[0]->getEventTime();
     646     17523426 :             if (!isDepart && leaderOut > tleave && overtake()) {
     647           20 :                 if (cars.size() == 1) {
     648            4 :                     MSGlobals::gMesoNet->removeLeaderCar(cars[0]);
     649              :                     newLeader = veh;
     650              :                 }
     651           20 :                 cars.insert(cars.begin() + 1, veh);
     652              :             } else {
     653     17523406 :                 tleave = MAX2(leaderOut + tauWithVehLength(myTau_ff, cars[0]->getVehicleType().getLengthWithGap(), cars[0]->getVehicleType().getCarFollowModel().getHeadwayTime()), tleave);
     654     17523406 :                 cars.insert(cars.begin(), veh);
     655              :             }
     656              :         }
     657     23790250 :         myEdge.unlock();
     658     23790250 :         myNumVehicles++;
     659     23790250 :         if (!isDepart && !isTeleport) {
     660              :             // departs and teleports could take place anywhere on the edge so they should not block regular flow
     661              :             // the -1 facilitates interleaving of multiple streams
     662     23111709 :             q.setEntryBlockTime(time + tauWithVehLength(myTau_ff, veh->getVehicleType().getLengthWithGap(), veh->getVehicleType().getCarFollowModel().getHeadwayTime()) - 1);
     663              :         }
     664     23790250 :         q.setOccupancy(MIN2(myQueueCapacity, q.getOccupancy() + veh->getVehicleType().getLengthWithGap()));
     665              :         veh->setEventTime(tleave);
     666     23790250 :         veh->setSegment(this, qIdx);
     667              :     }
     668     23791582 :     addReminders(veh);
     669     23791582 :     if (isDepart) {
     670       677568 :         veh->onDepart();
     671       677568 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_DEPARTED);
     672     23114014 :     } else if (newEdge) {
     673      2754386 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
     674              :     } else {
     675     20359628 :         veh->activateReminders(MSMoveReminder::NOTIFICATION_SEGMENT);
     676              :     }
     677     23791582 :     if (veh->isParking()) {
     678         1332 :         MSGlobals::gMesoNet->addLeaderCar(veh, nullptr);
     679              :     } else {
     680     23790250 :         if (newLeader != nullptr) {
     681      6266828 :             MSGlobals::gMesoNet->addLeaderCar(newLeader, getLink(newLeader));
     682              :         }
     683              :     }
     684              : }
     685              : 
     686              : 
     687              : bool
     688         8674 : MESegment::vaporizeAnyCar(SUMOTime currentTime, const MSDetectorFileOutput* filter) {
     689         9214 :     for (const Queue& q : myQueues) {
     690         8688 :         if (q.size() > 0) {
     691         8148 :             for (MEVehicle* const veh : q.getVehicles()) {
     692         8148 :                 if (filter->vehicleApplies(*veh)) {
     693         8148 :                     MSGlobals::gMesoNet->removeLeaderCar(veh);
     694         8148 :                     MSGlobals::gMesoNet->changeSegment(veh, currentTime + 1, &myVaporizationTarget, MSMoveReminder::NOTIFICATION_VAPORIZED_CALIBRATOR);
     695              :                     return true;
     696              :                 }
     697              :             }
     698              :         }
     699              :     }
     700              :     return false;
     701              : }
     702              : 
     703              : 
     704              : void
     705          346 : MESegment::setSpeedForQueue(double newSpeed, SUMOTime currentTime, SUMOTime blockTime, const std::vector<MEVehicle*>& vehs) {
     706          346 :     MEVehicle* v = vehs.back();
     707          346 :     v->updateDetectors(currentTime, false);
     708          346 :     SUMOTime newEvent = MAX2(newArrival(v, newSpeed, currentTime), blockTime);
     709          346 :     if (v->getEventTime() != newEvent) {
     710          324 :         MSGlobals::gMesoNet->removeLeaderCar(v);
     711              :         v->setEventTime(newEvent);
     712          324 :         MSGlobals::gMesoNet->addLeaderCar(v, getLink(v));
     713              :     }
     714         1069 :     for (std::vector<MEVehicle*>::const_reverse_iterator i = vehs.rbegin() + 1; i != vehs.rend(); ++i) {
     715          723 :         (*i)->updateDetectors(currentTime, false);
     716          723 :         newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + myTau_ff);
     717              :         //newEvent = MAX2(newArrival(*i, newSpeed, currentTime), newEvent + myTau_ff + (SUMOTime)((*(i - 1))->getVehicleType().getLength() / myTau_length));
     718          723 :         (*i)->setEventTime(newEvent);
     719              :     }
     720          346 : }
     721              : 
     722              : 
     723              : SUMOTime
     724         1069 : MESegment::newArrival(const MEVehicle* const v, double newSpeed, SUMOTime currentTime) {
     725              :     // since speed is only an upper bound pos may be to optimistic
     726         1069 :     const double pos = MIN2(myLength, STEPS2TIME(currentTime - v->getLastEntryTime()) * v->getSpeed());
     727              :     // traveltime may not be 0
     728         1069 :     double tt = (myLength - pos) / MAX2(newSpeed, MESO_MIN_SPEED);
     729         1069 :     return currentTime + MAX2(TIME2STEPS(tt), SUMOTime(1));
     730              : }
     731              : 
     732              : 
     733              : void
     734          971 : MESegment::setSpeed(double newSpeed, SUMOTime currentTime, double jamThresh, int qIdx) {
     735          971 :     recomputeJamThreshold(jamThresh);
     736              :     //myTau_length = MAX2(MESO_MIN_SPEED, newSpeed) * myEdge.getLanes().size() / TIME2STEPS(1);
     737              :     int i = 0;
     738         2024 :     for (const Queue& q : myQueues) {
     739         1053 :         if (q.size() != 0) {
     740          379 :             if (qIdx == -1 || qIdx == i) {
     741          346 :                 setSpeedForQueue(newSpeed, currentTime, q.getBlockTime(), q.getVehicles());
     742              :             }
     743              :         }
     744         1053 :         i++;
     745              :     }
     746          971 : }
     747              : 
     748              : 
     749              : SUMOTime
     750      1309049 : MESegment::getEventTime() const {
     751              :     SUMOTime result = SUMOTime_MAX;
     752      2903357 :     for (const Queue& q : myQueues) {
     753      1594308 :         if (q.size() != 0 && q.getVehicles().back()->getEventTime() < result) {
     754              :             result = q.getVehicles().back()->getEventTime();
     755              :         }
     756              :     }
     757      1309049 :     if (result < SUMOTime_MAX) {
     758       851140 :         return result;
     759              :     }
     760              :     return -1;
     761              : }
     762              : 
     763              : 
     764              : void
     765         5193 : MESegment::saveState(OutputDevice& out) const {
     766              :     bool write = false;
     767        10175 :     for (const Queue& q : myQueues) {
     768         5236 :         if (q.getBlockTime() != -1 || !q.getVehicles().empty()) {
     769              :             write = true;
     770              :             break;
     771              :         }
     772              :     }
     773         5193 :     if (write) {
     774          508 :         out.openTag(SUMO_TAG_SEGMENT).writeAttr(SUMO_ATTR_ID, getID());
     775          519 :         for (const Queue& q : myQueues) {
     776          530 :             out.openTag(SUMO_TAG_VIEWSETTINGS_VEHICLES).writeAttr(SUMO_ATTR_TIME, toString<SUMOTime>(q.getBlockTime()));
     777              :             out.writeAttr(SUMO_ATTR_VALUE, q.getVehicles());
     778          530 :             out.closeTag();
     779              :         }
     780          508 :         out.closeTag();
     781              :     }
     782         5193 : }
     783              : 
     784              : 
     785              : void
     786          277 : MESegment::clearState() {
     787          554 :     for (Queue& q : myQueues) {
     788              :         q.getModifiableVehicles().clear();
     789              :     }
     790          277 : }
     791              : 
     792              : void
     793          181 : MESegment::loadState(const std::vector<std::string>& vehIds, MSVehicleControl& vc, const SUMOTime block, const int queIdx) {
     794          181 :     Queue& q = myQueues[queIdx];
     795          389 :     for (const std::string& id : vehIds) {
     796          208 :         MEVehicle* v = static_cast<MEVehicle*>(vc.getVehicle(id));
     797              :         // vehicle could be removed due to options
     798          208 :         if (v != nullptr) {
     799              :             assert(v->getSegment() == this);
     800          206 :             q.getModifiableVehicles().push_back(v);
     801          206 :             myNumVehicles++;
     802          206 :             q.setOccupancy(q.getOccupancy() + v->getVehicleType().getLengthWithGap());
     803              :         }
     804              :     }
     805          181 :     if (q.size() != 0) {
     806              :         // add the last vehicle of this queue
     807              :         // !!! one question - what about the previously added vehicle? Is it stored twice?
     808           91 :         MEVehicle* veh = q.getVehicles().back();
     809           91 :         MSGlobals::gMesoNet->addLeaderCar(veh, getLink(veh));
     810              :     }
     811              :     q.setBlockTime(block);
     812          181 :     q.setOccupancy(MIN2(q.getOccupancy(), myQueueCapacity));
     813          181 : }
     814              : 
     815              : 
     816              : std::vector<const MEVehicle*>
     817           80 : MESegment::getVehicles() const {
     818              :     std::vector<const MEVehicle*> result;
     819          180 :     for (const Queue& q : myQueues) {
     820          100 :         result.insert(result.end(), q.getVehicles().begin(), q.getVehicles().end());
     821              :     }
     822           80 :     return result;
     823            0 : }
     824              : 
     825              : 
     826              : bool
     827      3582472 : MESegment::hasBlockedLeader() const {
     828      7227618 :     for (const Queue& q : myQueues) {
     829      3657519 :         if (q.size() > 0 && q.getVehicles().back()->getWaitingTime() > 0) {
     830              :             return true;
     831              :         }
     832              :     }
     833              :     return false;
     834              : }
     835              : 
     836              : 
     837              : double
     838            0 : MESegment::getFlow() const {
     839            0 :     return 3600 * getCarNumber() * getMeanSpeed() / myLength;
     840              : }
     841              : 
     842              : 
     843              : SUMOTime
     844     23791582 : MESegment::getLinkPenalty(const MEVehicle* veh) const {
     845     23791582 :     const MSLink* link = getLink(veh, myTLSPenalty || myCheckMinorPenalty);
     846     23791582 :     if (link != nullptr) {
     847              :         SUMOTime result = 0;
     848      1120619 :         if (link->isTLSControlled()) {
     849              :             result += link->getMesoTLSPenalty();
     850              :         }
     851              :         // minor tls links may get an additional penalty
     852       311726 :         if (!link->havePriority() &&
     853              :                 // do not apply penalty on top of tLSPenalty
     854      1120619 :                 !myTLSPenalty &&
     855              :                 // do not apply penalty if limited control is active
     856       276450 :                 (!MSGlobals::gMesoLimitedJunctionControl || limitedControlOverride(link))) {
     857       273980 :             result += myMinorPenalty;
     858              :         }
     859      1120619 :         return result;
     860              :     } else {
     861              :         return 0;
     862              :     }
     863              : }
     864              : 
     865              : 
     866              : double
     867            3 : MESegment::getWaitingSeconds() const {
     868              :     double result = 0;
     869            6 :     for (const Queue& q : myQueues) {
     870              :         // @note: only the leader currently accumulates waitingTime but this might change in the future
     871            4 :         for (const MEVehicle* veh : q.getVehicles()) {
     872            1 :             result += veh->getWaitingSeconds();
     873              :         }
     874              :     }
     875            3 :     return result;
     876              : }
     877              : 
     878              : 
     879              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1