1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file MSTriggeredRerouter.cpp
11 /// @author Daniel Krajzewicz
12 /// @author Jakob Erdmann
13 /// @author Michael Behrisch
14 /// @author Mirco Sturari
15 /// @date Mon, 25 July 2005
16 /// @version $Id$
17 ///
18 // Reroutes vehicles passing an edge
19 /****************************************************************************/
20
21
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #include <config.h>
26
27 #include <string>
28 #include <algorithm>
29 #include <utils/options/OptionsCont.h>
30 #include <utils/common/MsgHandler.h>
31 #include <utils/common/Command.h>
32 #include <utils/xml/SUMOXMLDefinitions.h>
33 #include <utils/common/UtilExceptions.h>
34 #include <utils/common/ToString.h>
35 #include <utils/common/StringUtils.h>
36 #include <utils/xml/SUMOSAXHandler.h>
37 #include <utils/router/DijkstraRouter.h>
38 #include <utils/common/RandHelper.h>
39 #include <utils/common/WrappingCommand.h>
40 #include <microsim/MSEdgeWeightsStorage.h>
41 #include <microsim/MSLane.h>
42 #include <microsim/MSVehicle.h>
43 #include <microsim/MSRoute.h>
44 #include <microsim/MSEdge.h>
45 #include <microsim/MSEventControl.h>
46 #include <microsim/MSNet.h>
47 #include <microsim/MSVehicleControl.h>
48 #include <microsim/MSGlobals.h>
49 #include <microsim/MSParkingArea.h>
50 #include <microsim/MSTransportable.h>
51 #include <microsim/devices/MSDevice_Routing.h>
52 #include <microsim/devices/MSRoutingEngine.h>
53 #include "MSTriggeredRerouter.h"
54
55 #include <mesosim/MELoop.h>
56 #include <mesosim/MESegment.h>
57
58 //#define DEBUG_REROUTER
59 #define DEBUG_PARKING
60 #define DEBUGCOND (veh.isSelected())
61
62 // ===========================================================================
63 // static member defintion
64 // ===========================================================================
65 MSEdge MSTriggeredRerouter::mySpecialDest_keepDestination("MSTriggeredRerouter_keepDestination", -1, EDGEFUNC_UNKNOWN, "", "", -1);
66 MSEdge MSTriggeredRerouter::mySpecialDest_terminateRoute("MSTriggeredRerouter_terminateRoute", -1, EDGEFUNC_UNKNOWN, "", "", -1);
67
68 // ===========================================================================
69 // method definitions
70 // ===========================================================================
MSTriggeredRerouter(const std::string & id,const MSEdgeVector & edges,double prob,const std::string & file,bool off,SUMOTime timeThreshold,const std::string & vTypes)71 MSTriggeredRerouter::MSTriggeredRerouter(const std::string& id,
72 const MSEdgeVector& edges,
73 double prob, const std::string& file, bool off,
74 SUMOTime timeThreshold,
75 const std::string& vTypes) :
76 MSTrigger(id),
77 MSMoveReminder(id),
78 SUMOSAXHandler(file),
79 myProbability(prob),
80 myUserProbability(prob),
81 myAmInUserMode(false),
82 myTimeThreshold(timeThreshold) {
83 // build actors
84 for (MSEdgeVector::const_iterator j = edges.begin(); j != edges.end(); ++j) {
85 if (MSGlobals::gUseMesoSim) {
86 MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(**j);
87 s->addDetector(this);
88 continue;
89 }
90 const std::vector<MSLane*>& destLanes = (*j)->getLanes();
91 for (std::vector<MSLane*>::const_iterator i = destLanes.begin(); i != destLanes.end(); ++i) {
92 (*i)->addMoveReminder(this);
93 }
94 }
95 if (off) {
96 setUserMode(true);
97 setUserUsageProbability(0);
98 }
99 const std::vector<std::string> vt = StringTokenizer(vTypes).getVector();
100 myVehicleTypes.insert(vt.begin(), vt.end());
101 }
102
103
~MSTriggeredRerouter()104 MSTriggeredRerouter::~MSTriggeredRerouter() {
105 }
106
107 // ------------ loading begin
108 void
myStartElement(int element,const SUMOSAXAttributes & attrs)109 MSTriggeredRerouter::myStartElement(int element,
110 const SUMOSAXAttributes& attrs) {
111 if (element == SUMO_TAG_INTERVAL) {
112 bool ok = true;
113 myCurrentIntervalBegin = attrs.getOptSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok, -1);
114 myCurrentIntervalEnd = attrs.getOptSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok, SUMOTime_MAX);
115 }
116 if (element == SUMO_TAG_DEST_PROB_REROUTE) {
117 // by giving probabilities of new destinations
118 // get the destination edge
119 std::string dest = attrs.getStringSecure(SUMO_ATTR_ID, "");
120 if (dest == "") {
121 throw ProcessError("MSTriggeredRerouter " + getID() + ": No destination edge id given.");
122 }
123 MSEdge* to = MSEdge::dictionary(dest);
124 if (to == nullptr) {
125 if (dest == "keepDestination") {
126 to = &mySpecialDest_keepDestination;
127 } else if (dest == "terminateRoute") {
128 to = &mySpecialDest_terminateRoute;
129 } else {
130 throw ProcessError("MSTriggeredRerouter " + getID() + ": Destination edge '" + dest + "' is not known.");
131 }
132 }
133 // get the probability to reroute
134 bool ok = true;
135 double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
136 if (!ok) {
137 throw ProcessError();
138 }
139 if (prob < 0) {
140 throw ProcessError("MSTriggeredRerouter " + getID() + ": Attribute 'probability' for destination '" + dest + "' is negative (must not).");
141 }
142 // add
143 myCurrentEdgeProb.add(to, prob);
144 }
145
146
147 if (element == SUMO_TAG_CLOSING_REROUTE) {
148 // by closing
149 std::string closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
150 MSEdge* closed = MSEdge::dictionary(closed_id);
151 if (closed == nullptr) {
152 throw ProcessError("MSTriggeredRerouter " + getID() + ": Edge '" + closed_id + "' to close is not known.");
153 }
154 myCurrentClosed.push_back(closed);
155 bool ok;
156 const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
157 const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
158 myCurrentPermissions = parseVehicleClasses(allow, disallow);
159 }
160
161 if (element == SUMO_TAG_CLOSING_LANE_REROUTE) {
162 // by closing lane
163 std::string closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
164 MSLane* closed = MSLane::dictionary(closed_id);
165 if (closed == nullptr) {
166 throw ProcessError("MSTriggeredRerouter " + getID() + ": Lane '" + closed_id + "' to close is not known.");
167 }
168 myCurrentClosedLanes.push_back(closed);
169 bool ok;
170 if (attrs.hasAttribute(SUMO_ATTR_ALLOW) || attrs.hasAttribute(SUMO_ATTR_DISALLOW)) {
171 const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
172 const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
173 myCurrentPermissions = parseVehicleClasses(allow, disallow);
174 } else {
175 // lane closing only makes sense if the lane really receives reduced
176 // permissions
177 myCurrentPermissions = SVC_AUTHORITY;
178 }
179 }
180
181 if (element == SUMO_TAG_ROUTE_PROB_REROUTE) {
182 // by explicit rerouting using routes
183 // check if route exists
184 std::string routeStr = attrs.getStringSecure(SUMO_ATTR_ID, "");
185 if (routeStr == "") {
186 throw ProcessError("MSTriggeredRerouter " + getID() + ": No route id given.");
187 }
188 const MSRoute* route = MSRoute::dictionary(routeStr);
189 if (route == nullptr) {
190 throw ProcessError("MSTriggeredRerouter " + getID() + ": Route '" + routeStr + "' does not exist.");
191 }
192
193 // get the probability to reroute
194 bool ok = true;
195 double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
196 if (!ok) {
197 throw ProcessError();
198 }
199 if (prob < 0) {
200 throw ProcessError("MSTriggeredRerouter " + getID() + ": Attribute 'probability' for route '" + routeStr + "' is negative (must not).");
201 }
202 // add
203 myCurrentRouteProb.add(route, prob);
204 }
205
206 if (element == SUMO_TAG_PARKING_ZONE_REROUTE) {
207 // by giving probabilities of new destinations
208 // get the destination edge
209 std::string parkingarea = attrs.getStringSecure(SUMO_ATTR_ID, "");
210 if (parkingarea == "") {
211 throw ProcessError("MSTriggeredRerouter " + getID() + ": No parking area id given.");
212 }
213 MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(parkingarea, SUMO_TAG_PARKING_AREA));
214 if (pa == nullptr) {
215 throw ProcessError("MSTriggeredRerouter " + getID() + ": Parking area '" + parkingarea + "' is not known.");
216 }
217 // get the probability to reroute
218 bool ok = true;
219 const double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
220 if (!ok) {
221 throw ProcessError();
222 }
223 if (prob < 0) {
224 throw ProcessError("MSTriggeredRerouter " + getID() + ": Attribute 'probability' for destination '" + parkingarea + "' is negative (must not).");
225 }
226 const bool visible = attrs.getOpt<bool>(SUMO_ATTR_VISIBLE, getID().c_str(), ok, false);
227 // add
228 myCurrentParkProb.add(std::make_pair(pa, visible), prob);
229 //MSEdge* to = &(pa->getLane().getEdge());
230 //myCurrentEdgeProb.add(prob, to);
231 }
232 }
233
234
235 void
myEndElement(int element)236 MSTriggeredRerouter::myEndElement(int element) {
237 if (element == SUMO_TAG_INTERVAL) {
238 RerouteInterval ri;
239 ri.begin = myCurrentIntervalBegin;
240 ri.end = myCurrentIntervalEnd;
241 ri.closed = myCurrentClosed;
242 ri.closedLanes = myCurrentClosedLanes;
243 ri.edgeProbs = myCurrentEdgeProb;
244 ri.routeProbs = myCurrentRouteProb;
245 ri.permissions = myCurrentPermissions;
246 ri.parkProbs = myCurrentParkProb;
247 if (ri.closedLanes.size() > 0) {
248 // collect edges that are affect by a closed lane
249 std::set<MSEdge*> affected;
250 for (std::vector<MSLane*>::iterator l = ri.closedLanes.begin(); l != ri.closedLanes.end(); ++l) {
251 affected.insert(&((*l)->getEdge()));
252 }
253 ri.closedLanesAffected.insert(ri.closedLanesAffected.begin(), affected.begin(), affected.end());
254 }
255 myCurrentClosed.clear();
256 myCurrentClosedLanes.clear();
257 myCurrentEdgeProb.clear();
258 myCurrentRouteProb.clear();
259 myCurrentParkProb.clear();
260 myIntervals.push_back(ri);
261 myIntervals.back().id = (long long)&myIntervals.back();
262 if (!(ri.closed.empty() && ri.closedLanes.empty()) && ri.permissions != SVCAll) {
263 MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
264 new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), ri.begin);
265 }
266 }
267 }
268
269
270 // ------------ loading end
271
272
273 SUMOTime
setPermissions(const SUMOTime currentTime)274 MSTriggeredRerouter::setPermissions(const SUMOTime currentTime) {
275 for (std::vector<RerouteInterval>::iterator i = myIntervals.begin(); i != myIntervals.end(); ++i) {
276 if (i->begin == currentTime && !(i->closed.empty() && i->closedLanes.empty()) && i->permissions != SVCAll) {
277 for (MSEdgeVector::iterator e = i->closed.begin(); e != i->closed.end(); ++e) {
278 for (std::vector<MSLane*>::const_iterator l = (*e)->getLanes().begin(); l != (*e)->getLanes().end(); ++l) {
279 //std::cout << SIMTIME << " closing: intervalID=" << i->id << " lane=" << (*l)->getID() << " prevPerm=" << getVehicleClassNames((*l)->getPermissions()) << " new=" << getVehicleClassNames(i->permissions) << "\n";
280 (*l)->setPermissions(i->permissions, i->id);
281 }
282 (*e)->rebuildAllowedLanes();
283 }
284 for (std::vector<MSLane*>::iterator l = i->closedLanes.begin(); l != i->closedLanes.end(); ++l) {
285 (*l)->setPermissions(i->permissions, i->id);
286 (*l)->getEdge().rebuildAllowedLanes();
287 }
288 MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
289 new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), i->end);
290 }
291 if (i->end == currentTime && !(i->closed.empty() && i->closedLanes.empty()) && i->permissions != SVCAll) {
292 for (MSEdgeVector::iterator e = i->closed.begin(); e != i->closed.end(); ++e) {
293 for (std::vector<MSLane*>::const_iterator l = (*e)->getLanes().begin(); l != (*e)->getLanes().end(); ++l) {
294 (*l)->resetPermissions(i->id);
295 //std::cout << SIMTIME << " opening: intervalID=" << i->id << " lane=" << (*l)->getID() << " restore prevPerm=" << getVehicleClassNames((*l)->getPermissions()) << "\n";
296 }
297 (*e)->rebuildAllowedLanes();
298 }
299 for (std::vector<MSLane*>::iterator l = i->closedLanes.begin(); l != i->closedLanes.end(); ++l) {
300 (*l)->resetPermissions(i->id);
301 (*l)->getEdge().rebuildAllowedLanes();
302 }
303 }
304 }
305 return 0;
306 }
307
308
309 const MSTriggeredRerouter::RerouteInterval*
getCurrentReroute(SUMOTime time,SUMOVehicle & veh) const310 MSTriggeredRerouter::getCurrentReroute(SUMOTime time, SUMOVehicle& veh) const {
311 for (std::vector<RerouteInterval>::const_iterator i = myIntervals.begin(); i != myIntervals.end(); ++i) {
312 if (i->begin <= time && i->end > time) {
313 if (
314 // destProbReroute
315 i->edgeProbs.getOverallProb() > 0 ||
316 // routeProbReroute
317 i->routeProbs.getOverallProb() > 0 ||
318 // parkingZoneReroute
319 i->parkProbs.getOverallProb() > 0 ||
320 // affected by closingReroute
321 veh.getRoute().containsAnyOf(i->closed) ||
322 // affected by closingLaneReroute
323 veh.getRoute().containsAnyOf(i->closedLanesAffected)) {
324 return &*i;
325 }
326 }
327 }
328 return nullptr;
329 }
330
331
332 const MSTriggeredRerouter::RerouteInterval*
getCurrentReroute(SUMOTime time) const333 MSTriggeredRerouter::getCurrentReroute(SUMOTime time) const {
334 for (std::vector<RerouteInterval>::const_iterator i = myIntervals.begin(); i != myIntervals.end(); ++i) {
335 if (i->begin <= time && i->end > time) {
336 if (i->parkProbs.getOverallProb() != 0 || i->edgeProbs.getOverallProb() != 0 || i->routeProbs.getOverallProb() != 0 || !i->closed.empty()) {
337 return &*i;
338 }
339 }
340 }
341 return nullptr;
342 }
343
344
345 bool
notifyMove(SUMOTrafficObject & veh,double,double,double)346 MSTriggeredRerouter::notifyMove(SUMOTrafficObject& veh, double /*oldPos*/,
347 double /*newPos*/, double /*newSpeed*/) {
348 return notifyEnter(veh, NOTIFICATION_JUNCTION);
349 }
350
351
352 bool
notifyLeave(SUMOTrafficObject &,double,MSMoveReminder::Notification reason,const MSLane *)353 MSTriggeredRerouter::notifyLeave(SUMOTrafficObject& /*veh*/, double /*lastPos*/,
354 MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
355 return reason == NOTIFICATION_LANE_CHANGE;
356 }
357
358
359 bool
notifyEnter(SUMOTrafficObject & tObject,MSMoveReminder::Notification,const MSLane *)360 MSTriggeredRerouter::notifyEnter(SUMOTrafficObject& tObject, MSMoveReminder::Notification /*reason*/, const MSLane* /* enteredLane */) {
361 if (!tObject.isVehicle()) {
362 return false;
363 }
364 SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
365 if (!vehicleApplies(veh)) {
366 return false;
367 }
368 // check whether the vehicle shall be rerouted
369 const SUMOTime time = MSNet::getInstance()->getCurrentTimeStep();
370 const MSTriggeredRerouter::RerouteInterval* rerouteDef = getCurrentReroute(time, veh);
371 if (rerouteDef == nullptr) {
372 return true; // an active interval could appear later
373 }
374 double prob = myAmInUserMode ? myUserProbability : myProbability;
375 if (RandHelper::rand() > prob) {
376 return false; // XXX another interval could appear later but we would have to track whether the current interval was already tried
377 }
378 if (myTimeThreshold > 0 && MAX2(veh.getWaitingTime(), veh.getAccumulatedWaitingTime()) < myTimeThreshold) {
379 return true; // waiting time may be reached later
380 }
381 // if we have a closingLaneReroute, only vehicles with a rerouting device can profit from rerouting (otherwise, edge weights will not reflect local jamming)
382 const bool hasReroutingDevice = veh.getDevice(typeid(MSDevice_Routing)) != nullptr;
383 if (rerouteDef->closedLanes.size() > 0 && !hasReroutingDevice) {
384 return true; // an active interval could appear later
385 }
386 // get vehicle params
387 const MSRoute& route = veh.getRoute();
388 const MSEdge* lastEdge = route.getLastEdge();
389 #ifdef DEBUG_REROUTER
390 if (DEBUGCOND) {
391 std::cout << SIMTIME << " veh=" << veh.getID() << " check rerouter " << getID() << " lane=" << veh.getLane()->getID() << " edge=" << veh.getEdge()->getID() << " finalEdge=" << lastEdge->getID() << " arrivalPos=" << veh.getArrivalPos() << "\n";
392 }
393 #endif
394
395 if (rerouteDef->parkProbs.getOverallProb() > 0) {
396 bool newDestination = false;
397 ConstMSEdgeVector newRoute;
398 MSParkingArea* newParkingArea = rerouteParkingArea(rerouteDef, veh, newDestination, newRoute);
399 if (newParkingArea != nullptr) {
400 // adapt plans of any riders
401 for (MSTransportable* p : veh.getPersons()) {
402 p->rerouteParkingArea(veh.getNextParkingArea(), newParkingArea);
403 }
404
405 if (newDestination) {
406 // update arrival parameters
407 SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
408 *newParameter = veh.getParameter();
409 newParameter->arrivalPosProcedure = ARRIVAL_POS_GIVEN;
410 newParameter->arrivalPos = newParkingArea->getEndLanePosition();
411 veh.replaceParameter(newParameter);
412 }
413
414 SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
415 ? MSRoutingEngine::getRouterTT(rerouteDef->closed)
416 : MSNet::getInstance()->getRouterTT(rerouteDef->closed);
417 const double routeCost = router.recomputeCosts(newRoute, &veh, MSNet::getInstance()->getCurrentTimeStep());
418 ConstMSEdgeVector prevEdges(veh.getCurrentRouteEdge(), veh.getRoute().end());
419 const double previousCost = router.recomputeCosts(prevEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
420 const double savings = previousCost - routeCost;
421 //if (getID() == "ego") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
422 // << " prevEdges=" << toString(prevEdges)
423 // << " newEdges=" << toString(edges)
424 // << "\n";
425
426 std::string errorMsg;
427 if (veh.replaceParkingArea(newParkingArea, errorMsg)) {
428 veh.replaceRouteEdges(newRoute, routeCost, savings, getID() + ":" + toString(SUMO_TAG_PARKING_ZONE_REROUTE), false, false, false);
429 } else {
430 WRITE_WARNING("Vehicle '" + veh.getID() + "' at rerouter '" + getID()
431 + "' could not reroute to new parkingArea '" + newParkingArea->getID()
432 + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
433 }
434 }
435 return false;
436 }
437
438 // get rerouting params
439 const MSRoute* newRoute = rerouteDef->routeProbs.getOverallProb() > 0 ? rerouteDef->routeProbs.get() : 0;
440 // we will use the route if given rather than calling our own dijsktra...
441 if (newRoute != nullptr) {
442 #ifdef DEBUG_REROUTER
443 if (DEBUGCOND) {
444 std::cout << " replacedRoute from routeDist " << newRoute->getID() << "\n";
445 }
446 #endif
447 veh.replaceRoute(newRoute, getID());
448 return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
449 }
450 const MSEdge* newEdge = lastEdge;
451 // ok, try using a new destination
452 double newArrivalPos = -1;
453 const bool destUnreachable = std::find(rerouteDef->closed.begin(), rerouteDef->closed.end(), lastEdge) != rerouteDef->closed.end();
454 // if we have a closingReroute, only assign new destinations to vehicles which cannot reach their original destination
455 // if we have a closingLaneReroute, no new destinations should be assigned
456 if (rerouteDef->closed.size() == 0 || destUnreachable) {
457 newEdge = rerouteDef->edgeProbs.getOverallProb() > 0 ? rerouteDef->edgeProbs.get() : route.getLastEdge();
458 if (newEdge == &mySpecialDest_terminateRoute) {
459 newEdge = veh.getEdge();
460 newArrivalPos = veh.getPositionOnLane(); // instant arrival
461 } else if (newEdge == &mySpecialDest_keepDestination || newEdge == lastEdge) {
462 if (destUnreachable && rerouteDef->permissions == SVCAll) {
463 // if permissions aren't set vehicles will simply drive through
464 // the closing unless terminated. If the permissions are specified, assume that the user wants
465 // vehicles to stand and wait until the closing ends
466 WRITE_WARNING("Cannot keep destination edge '" + lastEdge->getID() + "' for vehicle '" + veh.getID() + "' due to closed edges. Terminating route.");
467 newEdge = veh.getEdge();
468 } else {
469 newEdge = lastEdge;
470 }
471 } else if (newEdge == nullptr) {
472 #ifdef DEBUG_REROUTER
473 if (DEBUGCOND) {
474 std::cout << " could not find new edge!\n";
475 }
476 #endif
477 assert(false); // this should never happen
478 newEdge = veh.getEdge();
479 }
480 }
481 // we have a new destination, let's replace the vehicle route (if it is affected)
482 if (rerouteDef->closed.size() == 0 || destUnreachable || veh.getRoute().containsAnyOf(rerouteDef->closed)) {
483 ConstMSEdgeVector edges;
484 SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
485 ? MSRoutingEngine::getRouterTT(rerouteDef->closed)
486 : MSNet::getInstance()->getRouterTT(rerouteDef->closed);
487 router.compute(
488 veh.getEdge(), newEdge, &veh, MSNet::getInstance()->getCurrentTimeStep(), edges);
489 const double routeCost = router.recomputeCosts(edges, &veh, MSNet::getInstance()->getCurrentTimeStep());
490 const bool useNewRoute = veh.replaceRouteEdges(edges, routeCost, 0, getID());
491 #ifdef DEBUG_REROUTER
492 if (DEBUGCOND) std::cout << " rerouting: newEdge=" << newEdge->getID() << " useNewRoute=" << useNewRoute << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
493 << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->closed) << "\n";
494 #endif
495 if (useNewRoute && newArrivalPos != -1) {
496 // must be called here because replaceRouteEdges may also set the arrivalPos
497 veh.setArrivalPos(newArrivalPos);
498 }
499 }
500 return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
501 }
502
503
504 void
setUserMode(bool val)505 MSTriggeredRerouter::setUserMode(bool val) {
506 myAmInUserMode = val;
507 }
508
509
510 void
setUserUsageProbability(double prob)511 MSTriggeredRerouter::setUserUsageProbability(double prob) {
512 myUserProbability = prob;
513 }
514
515
516 bool
inUserMode() const517 MSTriggeredRerouter::inUserMode() const {
518 return myAmInUserMode;
519 }
520
521
522 double
getProbability() const523 MSTriggeredRerouter::getProbability() const {
524 return myAmInUserMode ? myUserProbability : myProbability;
525 }
526
527
528 double
getUserProbability() const529 MSTriggeredRerouter::getUserProbability() const {
530 return myUserProbability;
531 }
532
533
534 double
getWeight(SUMOVehicle & veh,const std::string param,const double defaultWeight) const535 MSTriggeredRerouter::getWeight(SUMOVehicle& veh, const std::string param, const double defaultWeight) const {
536 // get custom vehicle parameter
537 if (veh.getParameter().knowsParameter(param)) {
538 try {
539 return StringUtils::toDouble(veh.getParameter().getParameter(param, "-1"));
540 } catch (...) {
541 WRITE_WARNING("Invalid value '" + veh.getParameter().getParameter(param, "-1") + "' for vehicle parameter '" + param + "'");
542 }
543 } else {
544 // get custom vType parameter
545 if (veh.getVehicleType().getParameter().knowsParameter(param)) {
546 try {
547 return StringUtils::toDouble(veh.getVehicleType().getParameter().getParameter(param, "-1"));
548 } catch (...) {
549 WRITE_WARNING("Invalid value '" + veh.getVehicleType().getParameter().getParameter(param, "-1") + "' for vType parameter '" + param + "'");
550 }
551 }
552 }
553 //WRITE_MESSAGE("Vehicle '" +veh.getID() + "' does not supply vehicle parameter '" + param + "'. Using default of " + toString(defaultWeight) + "\n";
554 return defaultWeight;
555 }
556
557
558 MSParkingArea*
rerouteParkingArea(const MSTriggeredRerouter::RerouteInterval * rerouteDef,SUMOVehicle & veh,bool & newDestination,ConstMSEdgeVector & newRoute) const559 MSTriggeredRerouter::rerouteParkingArea(const MSTriggeredRerouter::RerouteInterval* rerouteDef,
560 SUMOVehicle& veh, bool& newDestination, ConstMSEdgeVector& newRoute) const {
561 // reroute destination from initial parking area to the near parking area
562 // if the next stop is a parking area, it is included in the current
563 // alternative set and if it can be observed to be full
564
565 MSParkingArea* nearParkArea = nullptr;
566 std::vector<ParkingAreaVisible> parks = rerouteDef->parkProbs.getVals();
567
568 // get vehicle params
569 MSParkingArea* destParkArea = veh.getNextParkingArea();
570 const MSRoute& route = veh.getRoute();
571
572 if (destParkArea == nullptr) {
573 // not driving towards a parkingArea
574 return nullptr;
575 }
576
577 bool destVisible = false;
578 for (auto paVis : parks) {
579 if (paVis.first == destParkArea
580 && (paVis.second
581 // if the vehicle is on the destParkArea edge it is always visible
582 || &(destParkArea->getLane().getEdge()) == veh.getEdge())) {
583 destVisible = true;
584 break;
585 }
586 }
587 if (!destVisible) {
588 // cannot determine destination occupancy
589 return nullptr;
590 }
591 if (destParkArea->getOccupancy() == destParkArea->getCapacity()) {
592 // if the current route ends at the parking area, the new route will
593 // also and at the new area
594 newDestination = (&destParkArea->getLane().getEdge() == route.getLastEdge()
595 && veh.getArrivalPos() >= destParkArea->getBeginLanePosition()
596 && veh.getArrivalPos() <= destParkArea->getEndLanePosition());
597
598 #ifdef DEBUG_PARKING
599 if (DEBUGCOND) {
600 std::cout << SIMTIME << " veh=" << veh.getID()
601 << " rerouteParkingArea dest=" << destParkArea->getID()
602 << " onDestEdge=" << (&(destParkArea->getLane().getEdge()) == veh.getEdge())
603 << " newDest=" << newDestination
604 << "\n";
605 }
606 #endif
607
608 typedef std::map<std::string, double> ParkingParamMap_t;
609 typedef std::map<MSParkingArea*, ParkingParamMap_t> MSParkingAreaMap_t;
610
611 ParkingParamMap_t weights;
612 std::map<MSParkingArea*, ConstMSEdgeVector> newRoutes;
613
614 // The probability of choosing this area inside the zone
615 weights["probability"] = getWeight(veh, "parking.probability.weight", 0.0);
616
617 // The capacity of this area
618 weights["capacity"] = getWeight(veh, "parking.capacity.weight", 0.0);
619
620 // The absolute number of free spaces
621 weights["absfreespace"] = getWeight(veh, "parking.absfreespace.weight", 0.0);
622
623 // The relative number of free spaces
624 weights["relfreespace"] = getWeight(veh, "parking.relfreespace.weight", 0.0);
625
626 // The distance to the new parking area
627 weights["distanceto"] = getWeight(veh, "parking.distanceto.weight", getWeight(veh, "parking.distance.weight", 1.0));
628
629 // The time to reach this area
630 weights["timeto"] = getWeight(veh, "parking.timeto.weight", 0.0);
631
632 // The distance from the new parking area
633 weights["distancefrom"] = getWeight(veh, "parking.distancefrom.weight", 0.0);
634
635 // The time to reach the end from this area
636 weights["timefrom"] = getWeight(veh, "parking.timefrom.weight", 0.0);
637
638 // a map stores maximum values to normalize parking values
639 ParkingParamMap_t maxValues;
640
641 maxValues["probability"] = 0.0;
642 maxValues["capacity"] = 0.0;
643 maxValues["absfreespace"] = 0.0;
644 maxValues["relfreespace"] = 0.0;
645 maxValues["distanceto"] = 0.0;
646 maxValues["timeto"] = 0.0;
647 maxValues["distancefrom"] = 0.0;
648 maxValues["timefrom"] = 0.0;
649
650 // a map stores elegible parking areas
651 MSParkingAreaMap_t parkAreas;
652
653 SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = MSNet::getInstance()->getRouterTT(rerouteDef->closed);
654
655 const std::vector<double>& probs = rerouteDef->parkProbs.getProbs();
656
657 const double brakeGap = veh.getBrakeGap();
658
659 for (int i = 0; i < (int)parks.size(); ++i) {
660 MSParkingArea* pa = parks[i].first;
661 const double prob = probs[i];
662 // alternative occupancy is randomized (but never full) if invisible
663 // current destination must be visible at this point
664 int paOccupancy = parks[i].second || pa == destParkArea ? pa->getOccupancy() : RandHelper::rand(pa->getCapacity());
665 if (paOccupancy < pa->getCapacity()) {
666
667 // a map stores the parking values
668 ParkingParamMap_t parkValues;
669
670 const RGBColor& c = route.getColor();
671 const MSEdge* parkEdge = &(pa->getLane().getEdge());
672
673 const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
674
675 // Compute the route from the current edge to the parking area edge
676 ConstMSEdgeVector edgesToPark;
677 router.compute(veh.getEdge(), parkEdge, &veh, MSNet::getInstance()->getCurrentTimeStep(), edgesToPark);
678
679 if (edgesToPark.size() > 0) {
680 // Compute the route from the parking area edge to the end of the route
681 ConstMSEdgeVector edgesFromPark;
682
683 const MSEdge* nextDestination = route.getLastEdge();
684 double nextPos = veh.getArrivalPos();
685 int nextDestinationIndex = route.size() - 1;
686 if (!newDestination) {
687 std::vector<std::pair<int, double> > stopIndices = veh.getStopIndices();
688 if (stopIndices.size() > 1) {
689 nextDestinationIndex = stopIndices[1].first;
690 nextDestination = route.getEdges()[nextDestinationIndex];
691 nextPos = stopIndices[1].second;
692
693 }
694 if (parkEdge == nextDestination && nextPos < pa->getEndLanePosition()) {
695 router.computeLooped(parkEdge, nextDestination, &veh, MSNet::getInstance()->getCurrentTimeStep(), edgesFromPark);
696 } else {
697 router.compute(parkEdge, nextDestination, &veh, MSNet::getInstance()->getCurrentTimeStep(), edgesFromPark);
698 }
699 }
700
701 if (edgesFromPark.size() > 0 || newDestination) {
702
703 parkValues["probability"] = prob;
704
705 if (parkValues["probability"] > maxValues["probability"]) {
706 maxValues["probability"] = parkValues["probability"];
707 }
708
709 parkValues["capacity"] = (double)(pa->getCapacity());
710 parkValues["absfreespace"] = (double)(pa->getCapacity() - paOccupancy);
711 parkValues["relfreespace"] = parkValues["absfreespace"] / parkValues["capacity"];
712
713 if (parkValues["capacity"] > maxValues["capacity"]) {
714 maxValues["capacity"] = parkValues["capacity"];
715 }
716
717 if (parkValues["absfreespace"] > maxValues["absfreespace"]) {
718 maxValues["absfreespace"] = parkValues["absfreespace"];
719 }
720
721 if (parkValues["relfreespace"] > maxValues["relfreespace"]) {
722 maxValues["relfreespace"] = parkValues["relfreespace"];
723 }
724
725 MSRoute routeToPark(route.getID() + "!topark#1", edgesToPark, false, &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), route.getStops());
726
727 // The distance from the current edge to the new parking area
728 parkValues["distanceto"] = routeToPark.getDistanceBetween(veh.getPositionOnLane(), pa->getBeginLanePosition(),
729 routeToPark.begin(), routeToPark.end() - 1, includeInternalLengths);
730
731 //std::cout << SIMTIME << " veh=" << veh.getID() << " candidate=" << pa->getID()
732 // << " distanceTo=" << parkValues["distanceto"]
733 // << " brakeGap=" << brakeGap
734 // << " routeToPark=" << toString(edgesToPark)
735 // << " fromPos=" << veh.getPositionOnLane()
736 // << " tPos=" << pa->getBeginLanePosition()
737 // << "\n";
738 if (parkValues["distanceto"] < brakeGap) {
739 //std::cout << " removed: pa too close\n";
740 // to close to stop for this parkingArea
741 continue;
742 }
743
744 // The time to reach the new parking area
745 parkValues["timeto"] = router.recomputeCosts(edgesToPark, &veh, MSNet::getInstance()->getCurrentTimeStep());
746
747 if (parkValues["distanceto"] > maxValues["distanceto"]) {
748 maxValues["distanceto"] = parkValues["distanceto"];
749 }
750
751 if (parkValues["timeto"] > maxValues["timeto"]) {
752 maxValues["timeto"] = parkValues["timeto"];
753 }
754
755 ConstMSEdgeVector newEdges = edgesToPark;
756
757 if (newDestination) {
758 parkValues["distancefrom"] = 0;
759 parkValues["timefrom"] = 0;
760 } else {
761 MSRoute routeFromPark(route.getID() + "!frompark#1", edgesFromPark, false,
762 &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), route.getStops());
763 // The distance from the new parking area to the end of the route
764 parkValues["distancefrom"] = routeFromPark.getDistanceBetween(pa->getBeginLanePosition(), routeFromPark.getLastEdge()->getLength(),
765 routeFromPark.begin(), routeFromPark.end() - 1, includeInternalLengths);
766 // The time to reach this area
767 parkValues["timefrom"] = router.recomputeCosts(edgesFromPark, &veh, MSNet::getInstance()->getCurrentTimeStep());
768 newEdges.insert(newEdges.end(), edgesFromPark.begin() + 1, edgesFromPark.end());
769 newEdges.insert(newEdges.end(), route.begin() + nextDestinationIndex + 1, route.end());
770 }
771
772 if (parkValues["distancefrom"] > maxValues["distancefrom"]) {
773 maxValues["distancefrom"] = parkValues["distancefrom"];
774 }
775
776 if (parkValues["timefrom"] > maxValues["timefrom"]) {
777 maxValues["timefrom"] = parkValues["timefrom"];
778 }
779
780 parkAreas[pa] = parkValues;
781 newRoutes[pa] = newEdges;
782
783 #ifdef DEBUG_PARKING
784 if (DEBUGCOND) {
785 std::cout << " altPA=" << pa->getID()
786 << " vals=" << joinToString(parkValues, " ", ":")
787 << "\n";
788 }
789 #endif
790 }
791 }
792 }
793 }
794
795 #ifdef DEBUG_PARKING
796 if (DEBUGCOND) {
797 std::cout << " maxValues=" << joinToString(maxValues, " ", ":") << "\n";
798 }
799 #endif
800
801 // minimum cost to get the parking area
802 double minParkingCost = 0.0;
803
804 for (MSParkingAreaMap_t::iterator it = parkAreas.begin(); it != parkAreas.end(); ++it) {
805 // get the parking values
806 ParkingParamMap_t parkValues = it->second;
807
808 // normalizing parking values with maximum values (we want to maximize some parameters then we reverse the value)
809 parkValues["probability"] = maxValues["probability"] > 0.0 ? 1.0 - parkValues["probability"] / maxValues["probability"] : 0.0;
810 parkValues["capacity"] = maxValues["capacity"] > 0.0 ? 1.0 - parkValues["capacity"] / maxValues["capacity"] : 0.0;
811 parkValues["absfreespace"] = maxValues["absfreespace"] > 0.0 ? 1.0 - parkValues["absfreespace"] / maxValues["absfreespace"] : 0.0;
812 parkValues["relfreespace"] = maxValues["relfreespace"] > 0.0 ? 1.0 - parkValues["relfreespace"] / maxValues["relfreespace"] : 0.0;
813
814 parkValues["distanceto"] = maxValues["distanceto"] > 0.0 ? parkValues["distanceto"] / maxValues["distanceto"] : 0.0;
815 parkValues["timeto"] = maxValues["timeto"] > 0.0 ? parkValues["timeto"] / maxValues["timeto"] : 0.0;
816
817 parkValues["distancefrom"] = maxValues["distancefrom"] > 0.0 ? parkValues["distancefrom"] / maxValues["distancefrom"] : 0.0;
818 parkValues["timefrom"] = maxValues["timefrom"] > 0.0 ? parkValues["timefrom"] / maxValues["timefrom"] : 0.0;
819
820 // get the parking area cost
821 double parkingCost = 0.0;
822
823 // sum every index with its weight
824 for (ParkingParamMap_t::iterator pc = parkValues.begin(); pc != parkValues.end(); ++pc) {
825 parkingCost += weights[pc->first] * pc->second;
826 }
827
828 // get the parking area with minimum cost
829 if (nearParkArea == nullptr || parkingCost < minParkingCost) {
830 minParkingCost = parkingCost;
831 nearParkArea = it->first;
832 newRoute = newRoutes[nearParkArea];
833 }
834
835 #ifdef DEBUG_PARKING
836 if (DEBUGCOND) {
837 std::cout << " altPA=" << it->first->getID() << " score=" << parkingCost << "\n";
838 }
839 #endif
840 }
841 }
842
843 #ifdef DEBUG_PARKING
844 if (DEBUGCOND) {
845 std::cout << " parkingResult=" << Named::getIDSecure(nearParkArea) << "\n";
846 }
847 #endif
848
849 return nearParkArea;
850 }
851
852
853 bool
vehicleApplies(const SUMOVehicle & veh) const854 MSTriggeredRerouter::vehicleApplies(const SUMOVehicle& veh) const {
855 if (myVehicleTypes.empty() || myVehicleTypes.count(veh.getVehicleType().getID()) > 0) {
856 return true;
857 } else {
858 std::set<std::string> vTypeDists = MSNet::getInstance()->getVehicleControl().getVTypeDistributionMembership(veh.getVehicleType().getID());
859 for (auto vTypeDist : vTypeDists) {
860 if (myVehicleTypes.count(vTypeDist) > 0) {
861 return true;
862 }
863 }
864 return false;
865 }
866 }
867 /****************************************************************************/
868
869