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 10936 : MSIdling_Stop::idle(MSDevice_Taxi* taxi) {
48 10936 : 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 428 : double brakeGap = 0;
56 : std::pair<const MSLane*, double> stopPos;
57 428 : if (MSGlobals::gUseMesoSim) {
58 : // stops are only checked in MESegment::receive so we need to put this onto the next segment
59 145 : MSBaseVehicle& veh = dynamic_cast<MSBaseVehicle&>(taxi->getHolder());
60 145 : MSRouteIterator ri = veh.getCurrentRouteEdge();
61 145 : MESegment* curSeg = MSGlobals::gMesoNet->getSegmentForEdge(**ri, veh.getPositionOnLane());
62 : MESegment* stopSeg = curSeg->getNextSegment();
63 145 : if (stopSeg == nullptr) {
64 71 : if ((ri + 1) != veh.getRoute().end()) {
65 4 : 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 78 : MESegment* seg = MSGlobals::gMesoNet->getSegmentForEdge(stopEdge);
75 152 : while (seg != stopSeg) {
76 74 : 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 361 : if (stopPos.first != nullptr) {
86 361 : SUMOVehicleParameter::Stop stop;
87 361 : if (MSGlobals::gUseMesoSim) {
88 : stop.edge = stopPos.first->getEdge().getID();
89 : } else {
90 : stop.lane = stopPos.first->getID();
91 : }
92 361 : stop.startPos = MAX2(0.0, stopPos.second - POSITION_EPS);
93 361 : stop.endPos = stopPos.second;
94 361 : if (MSGlobals::gUseMesoSim) {
95 : // meso needs the stop to be on the next segment
96 78 : stop.startPos += POSITION_EPS;
97 78 : stop.endPos += POSITION_EPS;
98 : }
99 : stop.actType = "idling";
100 361 : taxi->getHolder().addTraciStop(stop, errorOut);
101 361 : if (errorOut != "") {
102 0 : WRITE_WARNING(errorOut);
103 : }
104 361 : } 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 10869 : if (taxi->getHolder().hasStops()) {
115 10869 : MSStop& stop = taxi->getHolder().getNextStopMutable();
116 : SUMOVehicleParameter::Stop& pars = const_cast<SUMOVehicleParameter::Stop&>(stop.pars);
117 10869 : if (taxi->getHolder().getVehicleType().getContainerCapacity() > 0) {
118 660 : stop.containerTriggered = true;
119 660 : pars.containerTriggered = true;
120 : } else {
121 10209 : stop.triggered = true;
122 10209 : pars.triggered = true;
123 : }
124 10869 : pars.parametersSet |= STOP_TRIGGER_SET | STOP_PARKING_SET | STOP_END_SET;
125 10869 : pars.parking = ParkingType::OFFROAD;
126 10869 : if (MSGlobals::gUseMesoSim) {
127 2136 : MEVehicle& veh = dynamic_cast<MEVehicle&>(taxi->getHolder());
128 : // register triggered stop
129 2136 : veh.mayProceed();
130 : }
131 : }
132 : }
133 :
134 :
135 : // ===========================================================================
136 : // MSIdling_RandomCircling methods
137 : // ===========================================================================
138 :
139 : void
140 261199 : MSIdling_RandomCircling::idle(MSDevice_Taxi* taxi) {
141 : SUMOVehicle& veh = taxi->getHolder();
142 261199 : ConstMSEdgeVector edges = veh.getRoute().getEdges();
143 : ConstMSEdgeVector newEdges;
144 261199 : double remainingDist = -veh.getPositionOnLane();
145 : int remainingEdges = 0;
146 261199 : int routePos = veh.getRoutePosition();
147 261199 : const int routeLength = (int)edges.size();
148 838394 : while (routePos + 1 < routeLength && (remainingEdges < 2 || remainingDist < 200)) {
149 577195 : const MSEdge* edge = edges[routePos];
150 577195 : remainingDist += edge->getLength();
151 577195 : remainingEdges++;
152 : routePos++;
153 577195 : newEdges.push_back(edge);
154 : }
155 261199 : const MSEdge* lastEdge = edges.back();
156 261199 : newEdges.push_back(lastEdge);
157 : int added = 0;
158 279111 : while (remainingEdges < 2 || remainingDist < 200) {
159 17912 : remainingDist += lastEdge->getLength();
160 17912 : remainingEdges++;
161 17912 : MSEdgeVector successors = lastEdge->getSuccessors(veh.getVClass());
162 69463 : for (auto it = successors.begin(); it != successors.end();) {
163 51551 : if ((*it)->getFunction() == SumoXMLEdgeFunc::CONNECTOR) {
164 : it = successors.erase(it);
165 : } else {
166 : it++;
167 : }
168 : }
169 17912 : if (successors.size() == 0) {
170 0 : WRITE_WARNINGF(TL("Vehicle '%' ends idling in a cul-de-sac"), veh.getID());
171 : break;
172 : } else {
173 17912 : int nextIndex = RandHelper::rand((int)successors.size(), veh.getRNG());
174 17912 : newEdges.push_back(successors[nextIndex]);
175 17912 : lastEdge = newEdges.back();
176 17912 : added++;
177 : }
178 17912 : }
179 261199 : if (added > 0) {
180 : //std::cout << SIMTIME << " circleVeh=" << veh.getID() << " newEdges=" << toString(newEdges) << "\n";
181 35212 : veh.replaceRouteEdges(newEdges, -1, 0, "taxi:idling:randomCircling", false, false, false);
182 : }
183 261199 : }
184 :
185 : // ===========================================================================
186 : // MSIdling_TaxiStand methods
187 : // ===========================================================================
188 :
189 : void
190 317505 : MSIdling_TaxiStand::idle(MSDevice_Taxi* taxi) {
191 317505 : MSBaseVehicle& veh = dynamic_cast<MSBaseVehicle&>(taxi->getHolder());
192 :
193 317505 : const MSTriggeredRerouter::RerouteInterval* rerouteDef = myRerouter->getCurrentReroute(SIMSTEP);
194 317505 : if (rerouteDef == nullptr || rerouteDef->parkProbs.getVals().size() == 0) {
195 0 : if (!myHaveWarned) {
196 0 : WRITE_WARNINGF(TL("Could not determine taxi stand for vehicle '%' at time=%"), veh.getID(), time2string(SIMSTEP));
197 0 : myHaveWarned = true;
198 : }
199 0 : return;
200 : }
201 : MSStop* lastStop = nullptr;
202 317505 : if (veh.hasStops()) {
203 317164 : lastStop = &veh.getStop((int)veh.getStops().size() - 1);
204 : }
205 317164 : if (lastStop == nullptr || lastStop->parkingarea == nullptr) {
206 551 : const MSParkingArea* pa = dynamic_cast<MSParkingArea*>(rerouteDef->parkProbs.getVals().front().first);
207 551 : SUMOVehicleParameter::Stop stop;
208 551 : stop.lane = pa->getLane().getID();
209 551 : stop.startPos = pa->getBeginLanePosition();
210 551 : stop.endPos = pa->getEndLanePosition();
211 :
212 551 : if (taxi->getHolder().getVehicleType().getContainerCapacity() > 0) {
213 0 : stop.containerTriggered = true;
214 : } else {
215 551 : stop.triggered = true;
216 : }
217 : stop.actType = "idling";
218 : stop.parkingarea = pa->getID();
219 551 : stop.parking = ParkingType::OFFROAD;
220 551 : const int nextStopIndex = (int)veh.getStops().size();
221 : std::string error;
222 551 : if (!veh.insertStop(nextStopIndex, stop, "taxi:taxistand", false, error)) {
223 0 : WRITE_WARNING("Stop insertion failed for idling taxi '" + veh.getID() + "' (" + error + ").");
224 : } else {
225 : //std::cout << SIMTIME << " taxistandsVeh=" << veh.getID() << " driving to parkingArea " << pa->getID() << "\n";
226 551 : myRerouter->triggerRouting(veh, MSMoveReminder::NOTIFICATION_PARKING_REROUTE);
227 : }
228 317505 : } else if (!MSGlobals::gUseMesoSim) {
229 : //std::cout << SIMTIME << " taxistandsVeh=" << veh.getID() << " already driving to parkingArea\n";
230 : MSParkingArea* pa = lastStop->parkingarea;
231 315801 : if (taxi->getHolder().isStoppedTriggered() && pa != nullptr && pa->mustAdvance(taxi->getHolder().getVClass())) {
232 264655 : double vehPos = taxi->getHolder().getPositionOnLane();
233 264655 : double targetPos = pa->getLastFreePos(taxi->getHolder(), vehPos);
234 : //std::cout << SIMTIME << " veh=" << taxi->getHolder().getID() << " vehPos=" << vehPos << " targetPos=" << targetPos << " cap=" << pa->getCapacity() << " occ=" << pa->getOccupancyIncludingBlocked() << "\n";
235 264655 : if (targetPos > vehPos + POSITION_EPS) {
236 160 : taxi->getHolder().abortNextStop();
237 160 : idle(taxi);
238 : } else {
239 264495 : auto follower = veh.getFollower();
240 264494 : if (follower.first != nullptr && follower.first->getWaitingTime() > DELTA_T) {
241 : // advance in queue to unblock follower
242 490 : SUMOVehicleParameter::Stop stop = taxi->getHolder().getNextStop().pars;
243 490 : taxi->getHolder().abortNextStop();
244 : ConstMSEdgeVector loopedRoute;
245 490 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass());
246 490 : router.computeLooped(veh.getEdge(), veh.getEdge(), &veh, SIMSTEP, loopedRoute);
247 490 : veh.replaceRouteEdges(loopedRoute, -1, 0, "taxi:idling_unblock", false, false, false);
248 490 : stop.index = 1;
249 : std::string error;
250 490 : veh.addStop(stop, error);
251 490 : }
252 : }
253 : }
254 : }
255 : }
256 :
257 :
258 :
259 : /****************************************************************************/
|