LCOV - code coverage report
Current view: top level - src/microsim/devices - MSIdling.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 92.4 % 118 109
Test Date: 2026-05-24 16:29:35 Functions: 100.0 % 3 3

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2007-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    MSIdling.cpp
      15              : /// @author  Jakob Erdmann
      16              : /// @author  Mirko Barthauer
      17              : /// @date    17.08.2020
      18              : ///
      19              : // An algorithm that performs Idling for the taxi device
      20              : /****************************************************************************/
      21              : #include <config.h>
      22              : 
      23              : #include <limits>
      24              : #include <microsim/MSNet.h>
      25              : #include <microsim/MSEdge.h>
      26              : #include <microsim/MSLane.h>
      27              : #include <microsim/MSStop.h>
      28              : #include <microsim/MSParkingArea.h>
      29              : #include <microsim/transportables/MSTransportable.h>
      30              : #include <microsim/trigger/MSTriggeredRerouter.h>
      31              : #include <mesosim/MELoop.h>
      32              : #include <mesosim/MEVehicle.h>
      33              : #include "MSRoutingEngine.h"
      34              : #include "MSIdling.h"
      35              : 
      36              : //#define DEBUG_IDLING
      37              : //#define DEBUG_COND(obj) (obj->getHolder().getID() == "p0")
      38              : //#define DEBUG_COND(obj) (obj->getHolder().isSelected())
      39              : #define DEBUG_COND(obj) (true)
      40              : 
      41              : 
      42              : // ===========================================================================
      43              : // MSIdling_stop methods
      44              : // ===========================================================================
      45              : 
      46              : void
      47        10917 : MSIdling_Stop::idle(MSDevice_Taxi* taxi) {
      48        10917 :     if (!taxi->getHolder().hasStops()) {
      49              : #ifdef DEBUG_IDLING
      50              :         if (DEBUG_COND(taxi)) {
      51              :             std::cout << SIMTIME << " taxi=" << taxi->getHolder().getID() << " MSIdling_Stop add stop\n";
      52              :         }
      53              : #endif
      54              :         std::string errorOut;
      55          425 :         double brakeGap = 0;
      56              :         std::pair<const MSLane*, double> stopPos;
      57          425 :         if (MSGlobals::gUseMesoSim) {
      58              :             // stops are only checked in MESegment::receive so we need to put this onto the next segment
      59          142 :             MSBaseVehicle& veh = dynamic_cast<MSBaseVehicle&>(taxi->getHolder());
      60          142 :             MSRouteIterator ri = veh.getCurrentRouteEdge();
      61          142 :             MESegment* curSeg = MSGlobals::gMesoNet->getSegmentForEdge(**ri, veh.getPositionOnLane());
      62              :             MESegment* stopSeg = curSeg->getNextSegment();
      63          142 :             if (stopSeg == nullptr) {
      64           70 :                 if ((ri + 1) != veh.getRoute().end()) {
      65            3 :                     stopSeg = MSGlobals::gMesoNet->getSegmentForEdge(**(ri + 1), 0);
      66              :                 } else {
      67          201 :                     WRITE_WARNINGF(TL("Idle taxi '%' has no next segment to stop. time=%."), taxi->getHolder().getID(), time2string(SIMSTEP));
      68              :                     return;
      69              :                 }
      70              :             }
      71              :             // determine offset of stopSeg
      72              :             double stopOffset = 0;
      73              :             const MSEdge& stopEdge = stopSeg->getEdge();
      74           75 :             MESegment* seg = MSGlobals::gMesoNet->getSegmentForEdge(stopEdge);
      75          147 :             while (seg != stopSeg) {
      76           72 :                 stopOffset += seg->getLength();
      77              :                 seg = seg->getNextSegment();
      78              :             }
      79              :             stopPos = std::make_pair(stopEdge.getLanes()[0], stopOffset);
      80              :         } else {
      81          283 :             MSVehicle& veh = dynamic_cast<MSVehicle&>(taxi->getHolder());
      82          283 :             brakeGap = veh.getCarFollowModel().brakeGap(veh.getSpeed(), veh.getCarFollowModel().getMaxDecel(), 0.0);
      83          283 :             stopPos = veh.getLanePosAfterDist(brakeGap);
      84              :         }
      85          358 :         if (stopPos.first != nullptr) {
      86          358 :             SUMOVehicleParameter::Stop stop;
      87          358 :             if (MSGlobals::gUseMesoSim) {
      88              :                 stop.edge = stopPos.first->getEdge().getID();
      89              :             } else {
      90              :                 stop.lane = stopPos.first->getID();
      91              :             }
      92          358 :             stop.startPos = MAX2(0.0, stopPos.second - POSITION_EPS);
      93          358 :             stop.endPos = stopPos.second;
      94          358 :             if (MSGlobals::gUseMesoSim) {
      95              :                 // meso needs the stop to be on the next segment
      96           75 :                 stop.startPos += POSITION_EPS;
      97           75 :                 stop.endPos += POSITION_EPS;
      98              :             }
      99              :             stop.actType = "idling";
     100          358 :             taxi->getHolder().addTraciStop(stop, errorOut);
     101          358 :             if (errorOut != "") {
     102            0 :                 WRITE_WARNING(errorOut);
     103              :             }
     104          358 :         } else {
     105            0 :             WRITE_WARNINGF(TL("Idle taxi '%' could not stop within %m"), taxi->getHolder().getID(), toString(brakeGap));
     106              :         }
     107              :     } else {
     108              : #ifdef DEBUG_IDLING
     109              :         if (DEBUG_COND(taxi)) {
     110              :             std::cout << SIMTIME << " taxi=" << taxi->getHolder().getID() << " MSIdling_Stop reusing stop with duration " << time2string(taxi->getHolder().getNextStop().duration) << "\n";
     111              :         }
     112              : #endif
     113              :     }
     114        10850 :     if (taxi->getHolder().hasStops()) {
     115        10850 :         MSStop& stop = taxi->getHolder().getNextStopMutable();
     116              :         SUMOVehicleParameter::Stop& pars = const_cast<SUMOVehicleParameter::Stop&>(stop.pars);
     117        10850 :         if (taxi->getHolder().getVehicleType().getContainerCapacity() > 0) {
     118          660 :             stop.containerTriggered = true;
     119          660 :             pars.containerTriggered = true;
     120              :         } else {
     121        10190 :             stop.triggered = true;
     122        10190 :             pars.triggered = true;
     123              :         }
     124        10850 :         pars.parametersSet |= STOP_TRIGGER_SET | STOP_PARKING_SET | STOP_END_SET;
     125        10850 :         pars.parking = ParkingType::OFFROAD;
     126        10850 :         if (MSGlobals::gUseMesoSim) {
     127         2115 :             MEVehicle& veh = dynamic_cast<MEVehicle&>(taxi->getHolder());
     128              :             // register triggered stop
     129         2115 :             veh.mayProceed();
     130              :         }
     131              :     }
     132              : }
     133              : 
     134              : 
     135              : // ===========================================================================
     136              : // MSIdling_RandomCircling methods
     137              : // ===========================================================================
     138              : 
     139              : void
     140       281945 : MSIdling_RandomCircling::idle(MSDevice_Taxi* taxi) {
     141              :     SUMOVehicle& veh = taxi->getHolder();
     142       281945 :     ConstMSEdgeVector edges = veh.getRoute().getEdges();
     143              :     ConstMSEdgeVector newEdges;
     144       281945 :     double remainingDist = -veh.getPositionOnLane();
     145              :     int remainingEdges = 0;
     146       281945 :     int routePos = veh.getRoutePosition();
     147       281945 :     const int routeLength = (int)edges.size();
     148       899700 :     while (routePos + 1 < routeLength && (remainingEdges < 2 || remainingDist < 200)) {
     149       617755 :         const MSEdge* edge = edges[routePos];
     150       617755 :         remainingDist += edge->getLength();
     151       617755 :         remainingEdges++;
     152              :         routePos++;
     153       617755 :         newEdges.push_back(edge);
     154              :     }
     155       281945 :     const MSEdge* lastEdge = edges.back();
     156       281945 :     newEdges.push_back(lastEdge);
     157              :     int added = 0;
     158       301149 :     while (remainingEdges < 2 || remainingDist < 200) {
     159        19204 :         remainingDist += lastEdge->getLength();
     160        19204 :         remainingEdges++;
     161        19204 :         MSEdgeVector successors = lastEdge->getSuccessors(veh.getVClass());
     162        72668 :         for (auto it = successors.begin(); it != successors.end();) {
     163        53464 :             if ((*it)->getFunction() == SumoXMLEdgeFunc::CONNECTOR) {
     164              :                 it = successors.erase(it);
     165              :             } else {
     166              :                 it++;
     167              :             }
     168              :         }
     169        19204 :         if (gRoutingPreferences && successors.size() > 1) {
     170          612 :             const double threshPref = veh.getFloatParam("device.taxi.idleMinPref", false, 0);
     171              :             double maxPref = -std::numeric_limits<double>::max();
     172          918 :             for (const MSEdge* edge : successors) {
     173          612 :                 maxPref = MAX2(maxPref, edge->getPreference(veh.getVTypeParameter()));
     174              :             }
     175          306 :             if (maxPref >= threshPref) {
     176              :                 // there is at least one favoured successor, remove low preference edges
     177          918 :                 for (auto it = successors.begin(); it != successors.end();) {
     178          612 :                     if ((*it)->getPreference(veh.getVTypeParameter()) < threshPref) {
     179              :                         it = successors.erase(it);
     180              :                     } else {
     181              :                         it++;
     182              :                     }
     183              :                 }
     184              :             }
     185              :         }
     186        19204 :         if (successors.size() == 0) {
     187            0 :             WRITE_WARNINGF(TL("Vehicle '%' ends idling in a cul-de-sac"), veh.getID());
     188              :             break;
     189              :         } else {
     190        19204 :             int nextIndex = RandHelper::rand((int)successors.size(), veh.getRNG());
     191        19204 :             newEdges.push_back(successors[nextIndex]);
     192        19204 :             lastEdge = newEdges.back();
     193        19204 :             added++;
     194              :         }
     195        19204 :     }
     196       281945 :     if (added > 0) {
     197              :         //std::cout << SIMTIME << " circleVeh=" << veh.getID() << "  newEdges=" << toString(newEdges) << "\n";
     198        37688 :         veh.replaceRouteEdges(newEdges, -1, 0, "taxi:idling:randomCircling", false, false, false);
     199              :     }
     200       281945 : }
     201              : 
     202              : // ===========================================================================
     203              : // MSIdling_TaxiStand methods
     204              : // ===========================================================================
     205              : 
     206              : void
     207       317653 : MSIdling_TaxiStand::idle(MSDevice_Taxi* taxi) {
     208       317653 :     MSBaseVehicle& veh = dynamic_cast<MSBaseVehicle&>(taxi->getHolder());
     209              : 
     210       317653 :     const MSTriggeredRerouter::RerouteInterval* rerouteDef = myRerouter->getCurrentReroute(SIMSTEP);
     211       317653 :     if (rerouteDef == nullptr || rerouteDef->parkProbs.getVals().size() == 0) {
     212            0 :         if (!myHaveWarned) {
     213            0 :             WRITE_WARNINGF(TL("Could not determine taxi stand for vehicle '%' at time=%"), veh.getID(), time2string(SIMSTEP));
     214            0 :             myHaveWarned = true;
     215              :         }
     216            0 :         return;
     217              :     }
     218              :     MSStop* lastStop = nullptr;
     219       317653 :     if (veh.hasStops()) {
     220       317307 :         lastStop = &veh.getStop((int)veh.getStops().size() - 1);
     221              :     }
     222       317307 :     if (lastStop == nullptr || lastStop->parkingarea == nullptr) {
     223          566 :         const MSParkingArea* pa = dynamic_cast<MSParkingArea*>(rerouteDef->parkProbs.getVals().front().first);
     224          566 :         SUMOVehicleParameter::Stop stop;
     225          566 :         stop.lane = pa->getLane().getID();
     226          566 :         stop.startPos = pa->getBeginLanePosition();
     227          566 :         stop.endPos = pa->getEndLanePosition();
     228              : 
     229          566 :         if (taxi->getHolder().getVehicleType().getContainerCapacity() > 0) {
     230            0 :             stop.containerTriggered = true;
     231              :         } else {
     232          566 :             stop.triggered = true;
     233              :         }
     234              :         stop.actType = "idling";
     235              :         stop.parkingarea = pa->getID();
     236          566 :         stop.parking = ParkingType::OFFROAD;
     237          566 :         const int nextStopIndex = (int)veh.getStops().size();
     238              :         std::string error;
     239          566 :         if (!veh.insertStop(nextStopIndex, stop, "taxi:taxistand", false, error)) {
     240            0 :             WRITE_WARNING("Stop insertion failed for idling taxi '" + veh.getID() + "' (" + error + ").");
     241              :         } else {
     242              :             //std::cout << SIMTIME << " taxistandsVeh=" << veh.getID() << "  driving to parkingArea " << pa->getID() << "\n";
     243          566 :             myRerouter->triggerRouting(veh, MSMoveReminder::NOTIFICATION_PARKING_REROUTE);
     244              :         }
     245       317653 :     } else if (!MSGlobals::gUseMesoSim) {
     246              :         //std::cout << SIMTIME << " taxistandsVeh=" << veh.getID() << "  already driving to parkingArea\n";
     247              :         MSParkingArea* pa = lastStop->parkingarea;
     248       315801 :         if (taxi->getHolder().isStoppedTriggered() && pa != nullptr && pa->mustAdvance(taxi->getHolder().getVClass())) {
     249       264655 :             double vehPos = taxi->getHolder().getPositionOnLane();
     250       264655 :             double targetPos = pa->getLastFreePos(taxi->getHolder(), vehPos);
     251              :             //std::cout << SIMTIME << " veh=" << taxi->getHolder().getID() << " vehPos=" << vehPos << " targetPos=" << targetPos << " cap=" << pa->getCapacity() << " occ=" << pa->getOccupancyIncludingBlocked() << "\n";
     252       264655 :             if (targetPos > vehPos + POSITION_EPS) {
     253          160 :                 taxi->getHolder().abortNextStop();
     254          160 :                 idle(taxi);
     255              :             } else {
     256       264495 :                 auto follower = veh.getFollower();
     257       264493 :                 if (follower.first != nullptr && follower.first->getWaitingTime() > DELTA_T) {
     258              :                     // advance in queue to unblock follower
     259          490 :                     SUMOVehicleParameter::Stop stop = taxi->getHolder().getNextStop().pars;
     260          490 :                     taxi->getHolder().abortNextStop();
     261              :                     ConstMSEdgeVector loopedRoute;
     262          490 :                     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass());
     263          490 :                     router.computeLooped(veh.getEdge(), veh.getEdge(), &veh, SIMSTEP, loopedRoute);
     264          490 :                     veh.replaceRouteEdges(loopedRoute, -1, 0, "taxi:idling_unblock", false, false, false);
     265          490 :                     stop.index = 1;
     266              :                     std::string error;
     267          490 :                     veh.addStop(stop, error);
     268          490 :                 }
     269              :             }
     270              :         }
     271              :     }
     272              : }
     273              : 
     274              : 
     275              : 
     276              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1