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