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 : /****************************************************************************/
|