LCOV - code coverage report
Current view: top level - src/mesosim - MELoop.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 129 133 97.0 %
Date: 2024-04-27 15:34:54 Functions: 15 16 93.8 %

          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    MELoop.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @date    Tue, May 2005
      17             : ///
      18             : // The main mesocopic simulation loop
      19             : /****************************************************************************/
      20             : #include <config.h>
      21             : 
      22             : #include <queue>
      23             : #include <vector>
      24             : #include <map>
      25             : #include <cmath>
      26             : 
      27             : #include <microsim/MSNet.h>
      28             : #include <microsim/MSEdge.h>
      29             : #include <microsim/MSGlobals.h>
      30             : #include <microsim/MSLane.h>
      31             : #include <microsim/MSVehicle.h>
      32             : #include <microsim/MSVehicleControl.h>
      33             : #include <utils/options/OptionsCont.h>
      34             : #include <utils/common/ToString.h>
      35             : #include <utils/common/FileHelpers.h>
      36             : #include <utils/common/SUMOTime.h>
      37             : #include <utils/common/RandHelper.h>
      38             : #include "MELoop.h"
      39             : #include "MESegment.h"
      40             : #include "MEVehicle.h"
      41             : 
      42             : 
      43             : // ===========================================================================
      44             : // method definitions
      45             : // ===========================================================================
      46        5198 : MELoop::MELoop(const SUMOTime recheckInterval) : myFullRecheckInterval(recheckInterval), myLinkRecheckInterval(TIME2STEPS(1)) {
      47        5198 : }
      48             : 
      49        5103 : MELoop::~MELoop() {
      50      262688 :     for (std::vector<MESegment*>::const_iterator j = myEdges2FirstSegments.begin(); j != myEdges2FirstSegments.end(); ++j) {
      51      861494 :         for (MESegment* s = *j; s != nullptr;) {
      52             :             MESegment* n = s->getNextSegment();
      53      603909 :             delete s;
      54             :             s = n;
      55             :         }
      56             :     }
      57        5103 : }
      58             : 
      59             : 
      60             : void
      61    10516206 : MELoop::simulate(SUMOTime tMax) {
      62    50604696 :     while (!myLeaderCars.empty()) {
      63    49378832 :         const SUMOTime time = myLeaderCars.begin()->first;
      64    49378832 :         std::vector<MEVehicle*> vehs = myLeaderCars[time];
      65             :         assert(time > tMax - DELTA_T || vehs.size() == 0);
      66    49378832 :         if (time > tMax) {
      67             :             return;
      68             :         }
      69             :         myLeaderCars.erase(time);
      70    82815160 :         for (std::vector<MEVehicle*>::const_iterator i = vehs.begin(); i != vehs.end(); ++i) {
      71    42726670 :             checkCar(*i);
      72             :             assert(myLeaderCars.empty() || myLeaderCars.begin()->first >= time);
      73             :         }
      74             :     }
      75             : }
      76             : 
      77             : 
      78             : SUMOTime
      79    42741983 : MELoop::changeSegment(MEVehicle* veh, SUMOTime leaveTime, MESegment* const toSegment, MSMoveReminder::Notification reason, const bool ignoreLink) const {
      80    42741983 :     int qIdx = 0;
      81             :     MESegment* const onSegment = veh->getSegment();
      82             :     if (MESegment::isInvalid(toSegment)) {
      83      762980 :         if (veh->isStoppedTriggered()) {
      84         576 :             return leaveTime + MAX2(SUMOTime(1), myLinkRecheckInterval);
      85             :         }
      86      762404 :         if (onSegment != nullptr) {
      87      760744 :             onSegment->send(veh, toSegment, qIdx, leaveTime, reason);
      88             :         } else {
      89        4988 :             WRITE_WARNINGF(TL("Vehicle '%' teleports beyond arrival edge '%', time=%."),
      90             :                            veh->getID(), veh->getEdge()->getID(), time2string(leaveTime));
      91             :         }
      92      762404 :         veh->setSegment(toSegment); // signal arrival
      93      762404 :         MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
      94      762404 :         return leaveTime;
      95             :     }
      96    41979003 :     const SUMOTime entry = toSegment->hasSpaceFor(veh, leaveTime, qIdx);
      97    41979003 :     if (entry == leaveTime && (ignoreLink || veh->mayProceed())) {
      98    32996449 :         if (onSegment != nullptr) {
      99    32995755 :             if (veh->getQueIndex() == MESegment::PARKING_QUEUE) { // parking or just aborted parking
     100         887 :                 if (veh->isParking()) {
     101         711 :                     veh->processStop();
     102             :                 }
     103         887 :                 veh->getEdge()->getLanes()[0]->removeParking(veh);  // TODO for GUI only
     104             :             } else {
     105    62328000 :                 onSegment->send(veh, toSegment, qIdx, leaveTime, onSegment->getNextSegment() == nullptr ? MSMoveReminder::NOTIFICATION_JUNCTION : MSMoveReminder::NOTIFICATION_SEGMENT);
     106             :             }
     107    32995755 :             toSegment->receive(veh, qIdx, leaveTime, false, ignoreLink, &onSegment->getEdge() != &toSegment->getEdge());
     108             :         } else {
     109        2120 :             WRITE_WARNINGF(TL("Vehicle '%' ends teleporting on edge '%':%, time=%."),
     110             :                            veh->getID(), toSegment->getEdge().getID(), toSegment->getIndex(), time2string(leaveTime));
     111             :             // this is not quite correct but suffices for interrogation by
     112             :             // subsequent methods (veh->getSpeed() needs segment != 0)
     113         694 :             veh->setSegment(myEdges2FirstSegments[veh->getEdge()->getNumericalID()]);
     114             :             // clean up detectors (do not add traffic data)
     115             :             // note: updateDatector is not called if leaveTime == getLastEntryTime()
     116         694 :             veh->updateDetectors(veh->getLastEntryTime(), true, MSMoveReminder::NOTIFICATION_TELEPORT);
     117         694 :             toSegment->receive(veh, qIdx, leaveTime, false, true, true);
     118             :         }
     119    32996449 :         return entry;
     120             :     }
     121     8982554 :     if (entry == leaveTime && !ignoreLink) { // this is a long way of saying !veh->mayProceed() (which is a costly call)
     122     7408424 :         return entry + MAX2(SUMOTime(1), myLinkRecheckInterval);
     123             :     }
     124             :     return entry;
     125             : }
     126             : 
     127             : 
     128             : void
     129    42726670 : MELoop::checkCar(MEVehicle* veh) {
     130             :     const SUMOTime leaveTime = veh->getEventTime();
     131             :     MESegment* const onSegment = veh->getSegment();
     132    42726670 :     MESegment* const toSegment = veh->getQueIndex() == MESegment::PARKING_QUEUE ? onSegment : nextSegment(onSegment, veh);
     133    42726670 :     const bool teleporting = (onSegment == nullptr); // is the vehicle currently teleporting?
     134             :     // @note reason is only evaluated if toSegment == nullptr
     135    42726670 :     const SUMOTime nextEntry = changeSegment(veh, leaveTime, toSegment, MSMoveReminder::NOTIFICATION_ARRIVED, teleporting);
     136    42726670 :     if (nextEntry == leaveTime) {
     137             :         return;
     138             :     }
     139     8978062 :     if (!veh->isStopped() && MSGlobals::gTimeToGridlock > 0 && veh->getWaitingTime() > MSGlobals::gTimeToGridlock) {
     140        4200 :         teleportVehicle(veh, toSegment);
     141        4200 :         return;
     142             :     }
     143     8973862 :     if (veh->getBlockTime() == SUMOTime_MAX && !veh->isStopped()) {
     144             :         veh->setBlockTime(leaveTime);
     145             :     }
     146     8973862 :     if (nextEntry == SUMOTime_MAX) {
     147             :         // all usable queues on the next segment are full
     148     1185634 :         SUMOTime newEventTime = MAX3(toSegment->getEventTime() + 1, leaveTime + 1, leaveTime + myFullRecheckInterval);
     149     1185634 :         if (MSGlobals::gTimeToGridlock > 0) {
     150             :             // if teleporting is enabled, make sure we look at the vehicle when the gridlock-time is up
     151      947497 :             newEventTime = MAX2(MIN2(newEventTime, veh->getBlockTime() + MSGlobals::gTimeToGridlock + 1), leaveTime + DELTA_T);
     152             :         }
     153             :         veh->setEventTime(newEventTime);
     154             :     } else {
     155             :         // receiving segment has recently received another vehicle or the junction is blocked
     156             :         veh->setEventTime(nextEntry);
     157             :     }
     158     8973862 :     addLeaderCar(veh, onSegment->getLink(veh));
     159             : }
     160             : 
     161             : 
     162             : void
     163        4200 : MELoop::teleportVehicle(MEVehicle* veh, MESegment* const toSegment) {
     164             :     const SUMOTime leaveTime = veh->getEventTime();
     165             :     MESegment* const onSegment = veh->getSegment();
     166        4200 :     if (MSGlobals::gRemoveGridlocked) {
     167          48 :         WRITE_WARNINGF(TL("Teleporting vehicle '%'; waited too long, from edge '%':%, time=%."),
     168             :                        veh->getID(), onSegment->getEdge().getID(), onSegment->getIndex(),
     169             :                        time2string(leaveTime));
     170          16 :         MSNet::getInstance()->getVehicleControl().registerTeleportJam();
     171             :         int qIdx = 0;
     172          16 :         onSegment->send(veh, nullptr, qIdx, leaveTime, MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED);
     173          16 :         veh->setSegment(nullptr);
     174          16 :         MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
     175          16 :         return;
     176             :     }
     177             :     const bool teleporting = (onSegment == nullptr); // is the vehicle already teleporting?
     178             :     // try to find a place on the current edge
     179             :     MESegment* teleSegment = toSegment->getNextSegment();
     180        9252 :     while (teleSegment != nullptr && changeSegment(veh, leaveTime, teleSegment, MSMoveReminder::NOTIFICATION_TELEPORT, true) != leaveTime) {
     181             :         // @caution the time to get to the next segment here is ignored XXX
     182             :         teleSegment = teleSegment->getNextSegment();
     183             :     }
     184        4184 :     if (teleSegment != nullptr) {
     185         436 :         if (!teleporting) {
     186             :             // we managed to teleport in a single jump
     187        1238 :             WRITE_WARNINGF(TL("Teleporting vehicle '%'; waited too long, from edge '%':% to edge '%':%, time=%."),
     188             :                            veh->getID(), onSegment->getEdge().getID(), onSegment->getIndex(),
     189             :                            teleSegment->getEdge().getID(), teleSegment->getIndex(), time2string(leaveTime));
     190         412 :             MSNet::getInstance()->getVehicleControl().registerTeleportJam();
     191             :         }
     192             :     } else {
     193             :         // teleport across the current edge and try insertion later
     194        3748 :         if (!teleporting) {
     195             :             int qIdx = 0;
     196             :             // announce start of multi-step teleport, arrival will be announced in changeSegment()
     197        7146 :             WRITE_WARNINGF(TL("Teleporting vehicle '%'; waited too long, from edge '%':%, time=%."),
     198             :                            veh->getID(), onSegment->getEdge().getID(), onSegment->getIndex(), time2string(leaveTime));
     199        2366 :             MSNet::getInstance()->getVehicleControl().registerTeleportJam();
     200             :             // remove from current segment
     201        2366 :             onSegment->send(veh, nullptr, qIdx, leaveTime, MSMoveReminder::NOTIFICATION_TELEPORT);
     202             :             // mark veh as teleporting
     203        2366 :             veh->setSegment(nullptr);
     204             :         }
     205             :         // @caution microsim uses current travel time teleport duration
     206       11244 :         const SUMOTime teleArrival = leaveTime + TIME2STEPS(veh->getEdge()->getLength() / MAX2(veh->getEdge()->getSpeedLimit(), NUMERICAL_EPS));
     207        3748 :         const bool atDest = veh->moveRoutePointer();
     208        3748 :         if (atDest) {
     209             :             // teleporting to end of route
     210        1660 :             changeSegment(veh, teleArrival, nullptr, MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED, true);
     211             :         } else {
     212             :             veh->setEventTime(teleArrival);
     213        2088 :             addLeaderCar(veh, nullptr);
     214             :             // teleporting vehicles must react to rerouters
     215        2088 :             getSegmentForEdge(*veh->getEdge())->addReminders(veh);
     216        2088 :             veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
     217             :         }
     218             :     }
     219             : }
     220             : 
     221             : 
     222             : void
     223    42734270 : MELoop::addLeaderCar(MEVehicle* veh, MSLink* link) {
     224    42734270 :     myLeaderCars[veh->getEventTime()].push_back(veh);
     225    42734270 :     veh->setApproaching(link);
     226    42734270 : }
     227             : 
     228             : 
     229             : void
     230           1 : MELoop::clearState() {
     231             :     myLeaderCars.clear();
     232           1 : }
     233             : 
     234             : 
     235             : bool
     236        8641 : MELoop::removeLeaderCar(MEVehicle* v) {
     237        8641 :     const auto candIt = myLeaderCars.find(v->getEventTime());
     238        8641 :     if (candIt != myLeaderCars.end()) {
     239        2492 :         std::vector<MEVehicle*>& cands = candIt->second;
     240        2492 :         auto it = find(cands.begin(), cands.end(), v);
     241        2492 :         if (it != cands.end()) {
     242             :             cands.erase(it);
     243             :             return true;
     244             :         }
     245             :     }
     246             :     return false;
     247             : }
     248             : 
     249             : 
     250             : void
     251           0 : MELoop::vaporizeCar(MEVehicle* v, MSMoveReminder::Notification reason) {
     252             :     int qIdx = 0;
     253           0 :     v->getSegment()->send(v, nullptr, qIdx, MSNet::getInstance()->getCurrentTimeStep(), reason);
     254           0 :     removeLeaderCar(v);
     255           0 : }
     256             : 
     257             : 
     258             : MESegment*
     259    42644251 : MELoop::nextSegment(MESegment* s, MEVehicle* v) {
     260    42644251 :     if (s != nullptr) { // vehicle is not teleporting
     261             :         MESegment* next = s->getNextSegment();
     262    42642175 :         if (next != nullptr) {
     263             :             // ok, the street continues
     264             :             return next;
     265             :         }
     266             :     }
     267             :     // we have to check the next edge in the vehicle's route
     268    12666604 :     const MSEdge* nextEdge = v->succEdge(1);
     269    12666604 :     if (nextEdge == nullptr) {
     270             :         // end of route
     271             :         return nullptr;
     272             :     }
     273    11913433 :     return myEdges2FirstSegments[nextEdge->getNumericalID()];
     274             : }
     275             : 
     276             : 
     277             : int
     278      375887 : MELoop::numSegmentsFor(const double length, const double sLength) {
     279      375887 :     int no = (int)floor(length / sLength + 0.5);
     280      375887 :     if (no == 0) { // assure there is at least one segment
     281             :         return 1;
     282             :     } else {
     283      161140 :         return no;
     284             :     }
     285             : }
     286             : 
     287             : 
     288             : void
     289      260454 : MELoop::buildSegmentsFor(const MSEdge& e, const OptionsCont& oc) {
     290      260454 :     const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(e.getEdgeType());
     291             :     const double length = e.getLength();
     292      260454 :     const int numSegments = numSegmentsFor(length, oc.getFloat("meso-edgelength"));
     293      260454 :     const double slength = length / (double)numSegments;
     294             :     MESegment* newSegment = nullptr;
     295             :     MESegment* nextSegment = nullptr;
     296      260454 :     const bool laneQueue = oc.getBool("meso-lane-queue");
     297      273371 :     bool multiQueue = laneQueue || (oc.getBool("meso-multi-queue") && e.getLanes().size() > 1 && e.getNumSuccessors() > 1);
     298      869345 :     for (int s = numSegments - 1; s >= 0; s--) {
     299     1217782 :         std::string id = e.getID() + ":" + toString(s);
     300      608891 :         newSegment = new MESegment(id, e, nextSegment, slength, e.getLanes()[0]->getSpeedLimit(), s, multiQueue, edgeType);
     301             :         multiQueue = laneQueue;
     302             :         nextSegment = newSegment;
     303             :     }
     304      520908 :     while (e.getNumericalID() >= static_cast<int>(myEdges2FirstSegments.size())) {
     305      260454 :         myEdges2FirstSegments.push_back(0);
     306             :     }
     307      260454 :     myEdges2FirstSegments[e.getNumericalID()] = newSegment;
     308      260454 : }
     309             : 
     310             : 
     311             : void
     312         160 : MELoop::updateSegmentsForEdge(const MSEdge& e) {
     313         160 :     if (e.getNumericalID() < (int)myEdges2FirstSegments.size()) {
     314         160 :         const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(e.getEdgeType());
     315         160 :         MESegment* s = myEdges2FirstSegments[e.getNumericalID()];
     316         400 :         while (s != nullptr) {
     317         240 :             s->initSegment(edgeType, e, s->getCapacity());
     318             :             s = s->getNextSegment();
     319             :         }
     320             :     }
     321         160 : }
     322             : 
     323             : 
     324             : MESegment*
     325    59478781 : MELoop::getSegmentForEdge(const MSEdge& e, double pos) {
     326    59478781 :     if (e.getNumericalID() >= (int)myEdges2FirstSegments.size()) {
     327             :         return nullptr;
     328             :     }
     329    59478761 :     MESegment* s = myEdges2FirstSegments[e.getNumericalID()];
     330    59478761 :     if (pos > 0) {
     331             :         double cpos = 0;
     332      781180 :         while (s->getNextSegment() != nullptr && cpos + s->getLength() < pos) {
     333             :             cpos += s->getLength();
     334             :             s = s->getNextSegment();
     335             :         }
     336             :     }
     337             :     return s;
     338             : }
     339             : 
     340             : 
     341             : bool
     342      195349 : MELoop::isEnteringRoundabout(const MSEdge& e) {
     343      415830 :     for (const MSEdge* succ : e.getSuccessors()) {
     344      220493 :         if (succ->isRoundabout()) {
     345             :             return true;
     346             :         }
     347             :     }
     348             :     return false;
     349             : }
     350             : 
     351             : 
     352             : /****************************************************************************/

Generated by: LCOV version 1.14