LCOV - code coverage report
Current view: top level - src/microsim/devices - MSIdling.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 89.0 % 91 81
Test Date: 2025-11-13 15:38:19 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-2025 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 "MSRoutingEngine.h"
      33              : #include "MSIdling.h"
      34              : 
      35              : //#define DEBUG_IDLING
      36              : //#define DEBUG_COND(obj) (obj->getHolder().getID() == "p0")
      37              : //#define DEBUG_COND(obj) (obj->getHolder().isSelected())
      38              : #define DEBUG_COND(obj) (true)
      39              : 
      40              : 
      41              : // ===========================================================================
      42              : // MSIdling_stop methods
      43              : // ===========================================================================
      44              : 
      45              : void
      46        10653 : MSIdling_Stop::idle(MSDevice_Taxi* taxi) {
      47        10653 :     if (!taxi->getHolder().hasStops()) {
      48              : #ifdef DEBUG_IDLING
      49              :         if (DEBUG_COND(taxi)) {
      50              :             std::cout << SIMTIME << " taxi=" << taxi->getHolder().getID() << " MSIdling_Stop add stop\n";
      51              :         }
      52              : #endif
      53              :         std::string errorOut;
      54          358 :         double brakeGap = 0;
      55              :         std::pair<const MSLane*, double> stopPos;
      56          358 :         if (MSGlobals::gUseMesoSim) {
      57              :             // stops are only checked in MESegment::receive so we need to put this onto the next segment
      58          123 :             MSBaseVehicle& veh = dynamic_cast<MSBaseVehicle&>(taxi->getHolder());
      59          123 :             MSRouteIterator ri = veh.getCurrentRouteEdge();
      60          123 :             MESegment* curSeg = MSGlobals::gMesoNet->getSegmentForEdge(**ri, veh.getPositionOnLane());
      61              :             MESegment* stopSeg = curSeg->getNextSegment();
      62          123 :             if (stopSeg == nullptr) {
      63           61 :                 if ((ri + 1) != veh.getRoute().end()) {
      64            0 :                     stopSeg = MSGlobals::gMesoNet->getSegmentForEdge(**(ri + 1), 0);
      65              :                 } else {
      66          183 :                     WRITE_WARNINGF(TL("Idle taxi '%' has no next segment to stop. time=%."), taxi->getHolder().getID(), time2string(SIMSTEP));
      67              :                     return;
      68              :                 }
      69              :             }
      70              :             // determine offset of stopSeg
      71              :             double stopOffset = 0;
      72              :             const MSEdge& stopEdge = stopSeg->getEdge();
      73           62 :             MESegment* seg = MSGlobals::gMesoNet->getSegmentForEdge(stopEdge);
      74          124 :             while (seg != stopSeg) {
      75           62 :                 stopOffset += seg->getLength();
      76              :                 seg = seg->getNextSegment();
      77              :             }
      78              :             stopPos = std::make_pair(stopEdge.getLanes()[0], stopOffset);
      79              :         } else {
      80          235 :             MSVehicle& veh = dynamic_cast<MSVehicle&>(taxi->getHolder());
      81          235 :             brakeGap = veh.getCarFollowModel().brakeGap(veh.getSpeed(), veh.getCarFollowModel().getMaxDecel(), 0.0);
      82          235 :             stopPos = veh.getLanePosAfterDist(brakeGap);
      83              :         }
      84          297 :         if (stopPos.first != nullptr) {
      85          297 :             SUMOVehicleParameter::Stop stop;
      86          297 :             if (MSGlobals::gUseMesoSim) {
      87              :                 stop.edge = stopPos.first->getEdge().getID();
      88              :             } else {
      89              :                 stop.lane = stopPos.first->getID();
      90              :             }
      91          297 :             stop.startPos = MAX2(0.0, stopPos.second - POSITION_EPS);
      92          297 :             stop.endPos = stopPos.second;
      93          297 :             if (MSGlobals::gUseMesoSim) {
      94              :                 // meso needs the stop to be on the next segment
      95           62 :                 stop.startPos += POSITION_EPS;
      96           62 :                 stop.endPos += POSITION_EPS;
      97              :             }
      98          297 :             if (taxi->getHolder().getVehicleType().getContainerCapacity() > 0) {
      99           24 :                 stop.containerTriggered = true;
     100              :             } else {
     101          273 :                 stop.triggered = true;
     102              :             }
     103              :             stop.actType = "idling";
     104          297 :             stop.parking = ParkingType::OFFROAD;
     105          297 :             taxi->getHolder().addTraciStop(stop, errorOut);
     106          297 :             if (errorOut != "") {
     107            0 :                 WRITE_WARNING(errorOut);
     108              :             }
     109          297 :         } else {
     110            0 :             WRITE_WARNINGF(TL("Idle taxi '%' could not stop within %m"), taxi->getHolder().getID(), toString(brakeGap));
     111              :         }
     112              :     } else {
     113        10295 :         MSStop& stop = taxi->getHolder().getNextStopMutable();
     114              : #ifdef DEBUG_IDLING
     115              :         if (DEBUG_COND(taxi)) {
     116              :             std::cout << SIMTIME << " taxi=" << taxi->getHolder().getID() << " MSIdling_Stop reusing stop with duration " << time2string(stop.duration) << "\n";
     117              :         }
     118              : #endif
     119        10295 :         if (taxi->getHolder().getVehicleType().getContainerCapacity() > 0) {
     120          636 :             stop.containerTriggered = true;
     121              :         } else {
     122         9659 :             stop.triggered = true;
     123              :         }
     124              :     }
     125              : }
     126              : 
     127              : 
     128              : // ===========================================================================
     129              : // MSIdling_RandomCircling methods
     130              : // ===========================================================================
     131              : 
     132              : void
     133       236095 : MSIdling_RandomCircling::idle(MSDevice_Taxi* taxi) {
     134              :     SUMOVehicle& veh = taxi->getHolder();
     135       236095 :     ConstMSEdgeVector edges = veh.getRoute().getEdges();
     136              :     ConstMSEdgeVector newEdges;
     137       236095 :     double remainingDist = -veh.getPositionOnLane();
     138              :     int remainingEdges = 0;
     139       236095 :     int routePos = veh.getRoutePosition();
     140       236095 :     const int routeLength = (int)edges.size();
     141       759839 :     while (routePos + 1 < routeLength && (remainingEdges < 2 || remainingDist < 200)) {
     142       523744 :         const MSEdge* edge = edges[routePos];
     143       523744 :         remainingDist += edge->getLength();
     144       523744 :         remainingEdges++;
     145              :         routePos++;
     146       523744 :         newEdges.push_back(edge);
     147              :     }
     148       236095 :     const MSEdge* lastEdge = edges.back();
     149       236095 :     newEdges.push_back(lastEdge);
     150              :     int added = 0;
     151       253647 :     while (remainingEdges < 2 || remainingDist < 200) {
     152        17552 :         remainingDist += lastEdge->getLength();
     153        17552 :         remainingEdges++;
     154        17552 :         MSEdgeVector successors = lastEdge->getSuccessors(veh.getVClass());
     155        67588 :         for (auto it = successors.begin(); it != successors.end();) {
     156        50036 :             if ((*it)->getFunction() == SumoXMLEdgeFunc::CONNECTOR) {
     157              :                 it = successors.erase(it);
     158              :             } else {
     159              :                 it++;
     160              :             }
     161              :         }
     162        17552 :         if (successors.size() == 0) {
     163            0 :             WRITE_WARNINGF(TL("Vehicle '%' ends idling in a cul-de-sac"), veh.getID());
     164              :             break;
     165              :         } else {
     166        17552 :             int nextIndex = RandHelper::rand((int)successors.size(), veh.getRNG());
     167        17552 :             newEdges.push_back(successors[nextIndex]);
     168        17552 :             lastEdge = newEdges.back();
     169        17552 :             added++;
     170              :         }
     171        17552 :     }
     172       236095 :     if (added > 0) {
     173              :         //std::cout << SIMTIME << " circleVeh=" << veh.getID() << "  newEdges=" << toString(newEdges) << "\n";
     174        34314 :         veh.replaceRouteEdges(newEdges, -1, 0, "taxi:idling:randomCircling", false, false, false);
     175              :     }
     176       236095 : }
     177              : 
     178              : // ===========================================================================
     179              : // MSIdling_TaxiStand methods
     180              : // ===========================================================================
     181              : 
     182              : void
     183         7280 : MSIdling_TaxiStand::idle(MSDevice_Taxi* taxi) {
     184         7280 :     MSBaseVehicle& veh = dynamic_cast<MSBaseVehicle&>(taxi->getHolder());
     185              : 
     186         7280 :     const MSTriggeredRerouter::RerouteInterval* rerouteDef = myRerouter->getCurrentReroute(SIMSTEP);
     187         7280 :     if (rerouteDef == nullptr || rerouteDef->parkProbs.getVals().size() == 0) {
     188            0 :         if (!myHaveWarned) {
     189            0 :             WRITE_WARNINGF(TL("Could not determine taxi stand for vehicle '%' at time=%"), veh.getID(), time2string(SIMSTEP));
     190            0 :             myHaveWarned = true;
     191              :         }
     192            0 :         return;
     193              :     }
     194              :     MSStop* lastStop = nullptr;
     195         7280 :     if (veh.hasStops()) {
     196         7214 :         lastStop = &veh.getStop((int)veh.getStops().size() - 1);
     197              :     }
     198         7214 :     if (lastStop == nullptr || lastStop->parkingarea == nullptr) {
     199          156 :         const MSParkingArea* pa = dynamic_cast<MSParkingArea*>(rerouteDef->parkProbs.getVals().front().first);
     200          156 :         SUMOVehicleParameter::Stop stop;
     201          156 :         stop.lane = pa->getLane().getID();
     202          156 :         stop.startPos = pa->getBeginLanePosition();
     203          156 :         stop.endPos = pa->getEndLanePosition();
     204              : 
     205          156 :         if (taxi->getHolder().getVehicleType().getContainerCapacity() > 0) {
     206            0 :             stop.containerTriggered = true;
     207              :         } else {
     208          156 :             stop.triggered = true;
     209              :         }
     210              :         stop.actType = "idling";
     211              :         stop.parkingarea = pa->getID();
     212          156 :         stop.parking = ParkingType::OFFROAD;
     213          156 :         const int nextStopIndex = (int)veh.getStops().size();
     214              :         std::string error;
     215          156 :         if (!veh.insertStop(nextStopIndex, stop, "taxi:taxistand", false, error)) {
     216            0 :             WRITE_WARNING("Stop insertion failed for idling taxi '" + veh.getID() + "' (" + error + ").");
     217              :         } else {
     218              :             //std::cout << SIMTIME << " taxistandsVeh=" << veh.getID() << "  driving to parkingArea " << pa->getID() << "\n";
     219          156 :             myRerouter->triggerRouting(veh, MSMoveReminder::NOTIFICATION_PARKING_REROUTE);
     220              :         }
     221          156 :     } else {
     222              :         //std::cout << SIMTIME << " taxistandsVeh=" << veh.getID() << "  already driving to parkingArea\n";
     223              :     }
     224              : }
     225              : 
     226              : 
     227              : 
     228              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1