Eclipse SUMO - Simulation of Urban MObility
MSTriggeredRerouter.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3// Copyright (C) 2001-2023 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/****************************************************************************/
21// Reroutes vehicles passing an edge
22/****************************************************************************/
23#include <config.h>
24
25#include <string>
26#include <algorithm>
27#ifdef HAVE_FOX
29#endif
42#include <microsim/MSLane.h>
43#include <microsim/MSVehicle.h>
44#include <microsim/MSRoute.h>
45#include <microsim/MSEdge.h>
47#include <microsim/MSNet.h>
49#include <microsim/MSGlobals.h>
51#include <microsim/MSStop.h>
55#include "MSTriggeredRerouter.h"
56
57#include <mesosim/MELoop.h>
58#include <mesosim/MESegment.h>
59
60//#define DEBUG_REROUTER
61//#define DEBUG_PARKING
62#define DEBUGCOND (veh.isSelected())
63//#define DEBUGCOND (true)
64//#define DEBUGCOND (veh.getID() == "")
65
66// ===========================================================================
67// static member definition
68// ===========================================================================
69MSEdge MSTriggeredRerouter::mySpecialDest_keepDestination("MSTriggeredRerouter_keepDestination", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", -1, 0);
70MSEdge MSTriggeredRerouter::mySpecialDest_terminateRoute("MSTriggeredRerouter_terminateRoute", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", -1, 0);
71std::map<std::string, MSTriggeredRerouter*> MSTriggeredRerouter::myInstances;
72
73// ===========================================================================
74// method definitions
75// ===========================================================================
77 const MSEdgeVector& edges, double prob, bool off,
78 SUMOTime timeThreshold, const std::string& vTypes) :
79 Named(id),
81 myEdges(edges),
82 myProbability(prob),
83 myUserProbability(prob),
84 myAmInUserMode(false),
85 myTimeThreshold(timeThreshold) {
86 myInstances[id] = this;
87 // build actors
88 for (MSEdgeVector::const_iterator j = edges.begin(); j != edges.end(); ++j) {
91 s->addDetector(this);
92 continue;
93 }
94 const std::vector<MSLane*>& destLanes = (*j)->getLanes();
95 for (std::vector<MSLane*>::const_iterator i = destLanes.begin(); i != destLanes.end(); ++i) {
96 (*i)->addMoveReminder(this);
97 }
98 }
99 if (off) {
100 setUserMode(true);
102 }
103 const std::vector<std::string> vt = StringTokenizer(vTypes).getVector();
104 myVehicleTypes.insert(vt.begin(), vt.end());
105}
106
107
109 myInstances.erase(getID());
110}
111
112
113// ------------ loading begin
114void
116 const SUMOSAXAttributes& attrs) {
117 if (element == SUMO_TAG_INTERVAL) {
118 bool ok = true;
121 }
122 if (element == SUMO_TAG_DEST_PROB_REROUTE) {
123 // by giving probabilities of new destinations
124 // get the destination edge
125 std::string dest = attrs.getStringSecure(SUMO_ATTR_ID, "");
126 if (dest == "") {
127 throw ProcessError(TLF("MSTriggeredRerouter %: No destination edge id given.", getID()));
128 }
129 MSEdge* to = MSEdge::dictionary(dest);
130 if (to == nullptr) {
131 if (dest == "keepDestination") {
133 } else if (dest == "terminateRoute") {
135 } else {
136 throw ProcessError("MSTriggeredRerouter " + getID() + ": Destination edge '" + dest + "' is not known.");
137 }
138 }
139 // get the probability to reroute
140 bool ok = true;
141 double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
142 if (!ok) {
143 throw ProcessError();
144 }
145 if (prob < 0) {
146 throw ProcessError("MSTriggeredRerouter " + getID() + ": Attribute 'probability' for destination '" + dest + "' is negative (must not).");
147 }
148 // add
149 myCurrentEdgeProb.add(to, prob);
150 }
151
152
153 if (element == SUMO_TAG_CLOSING_REROUTE) {
154 // by closing
155 std::string closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
156 MSEdge* closed = MSEdge::dictionary(closed_id);
157 if (closed == nullptr) {
158 throw ProcessError("MSTriggeredRerouter " + getID() + ": Edge '" + closed_id + "' to close is not known.");
159 }
160 myCurrentClosed.push_back(closed);
161 bool ok;
162 const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
163 const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
164 myCurrentPermissions = parseVehicleClasses(allow, disallow);
165 }
166
167 if (element == SUMO_TAG_CLOSING_LANE_REROUTE) {
168 // by closing lane
169 std::string closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
170 MSLane* closed = MSLane::dictionary(closed_id);
171 if (closed == nullptr) {
172 throw ProcessError("MSTriggeredRerouter " + getID() + ": Lane '" + closed_id + "' to close is not known.");
173 }
174 myCurrentClosedLanes.push_back(closed);
175 bool ok;
177 const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
178 const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
179 myCurrentPermissions = parseVehicleClasses(allow, disallow);
180 } else {
181 // lane closing only makes sense if the lane really receives reduced
182 // permissions
184 }
185 }
186
187 if (element == SUMO_TAG_ROUTE_PROB_REROUTE) {
188 // by explicit rerouting using routes
189 // check if route exists
190 std::string routeStr = attrs.getStringSecure(SUMO_ATTR_ID, "");
191 if (routeStr == "") {
192 throw ProcessError(TLF("MSTriggeredRerouter %: No route id given.", getID()));
193 }
194 ConstMSRoutePtr route = MSRoute::dictionary(routeStr);
195 if (route == nullptr) {
196 throw ProcessError("MSTriggeredRerouter " + getID() + ": Route '" + routeStr + "' does not exist.");
197 }
198
199 // get the probability to reroute
200 bool ok = true;
201 double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
202 if (!ok) {
203 throw ProcessError();
204 }
205 if (prob < 0) {
206 throw ProcessError("MSTriggeredRerouter " + getID() + ": Attribute 'probability' for route '" + routeStr + "' is negative (must not).");
207 }
208 // add
209 myCurrentRouteProb.add(route, prob);
210 }
211
212 if (element == SUMO_TAG_PARKING_AREA_REROUTE) {
213 // by giving probabilities of new destinations
214 // get the destination edge
215 std::string parkingarea = attrs.getStringSecure(SUMO_ATTR_ID, "");
216 if (parkingarea == "") {
217 throw ProcessError(TLF("MSTriggeredRerouter %: No parking area id given.", getID()));
218 }
220 if (pa == nullptr) {
221 throw ProcessError("MSTriggeredRerouter " + getID() + ": Parking area '" + parkingarea + "' is not known.");
222 }
223 // get the probability to reroute
224 bool ok = true;
225 const double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
226 if (!ok) {
227 throw ProcessError();
228 }
229 if (prob < 0) {
230 throw ProcessError("MSTriggeredRerouter " + getID() + ": Attribute 'probability' for destination '" + parkingarea + "' is negative (must not).");
231 }
232 const bool visible = attrs.getOpt<bool>(SUMO_ATTR_VISIBLE, getID().c_str(), ok, false);
233 // add
234 myCurrentParkProb.add(std::make_pair(pa, visible), prob);
235 //MSEdge* to = &(pa->getLane().getEdge());
236 //myCurrentEdgeProb.add(prob, to);
237 }
238}
239
240
241void
243 if (element == SUMO_TAG_INTERVAL) {
253 for (auto paVi : ri.parkProbs.getVals()) {
254 paVi.first->setNumAlternatives((int)ri.parkProbs.getVals().size() - 1);
255 }
256 if (ri.closedLanes.size() > 0) {
257 // collect edges that are affect by a closed lane
258 std::set<MSEdge*> affected;
259 for (const MSLane* const l : ri.closedLanes) {
260 affected.insert(&l->getEdge());
261 }
262 ri.closedLanesAffected.insert(ri.closedLanesAffected.begin(), affected.begin(), affected.end());
263 }
264 SUMOTime closingBegin = ri.begin;
265 SUMOTime simBegin = string2time(OptionsCont::getOptions().getString("begin"));
266 if (closingBegin < simBegin && ri.end > simBegin) {
267 // interval started before simulation begin but is still active at
268 // the start of the simulation
269 ri.begin = simBegin;
270 }
271 myCurrentClosed.clear();
272 myCurrentClosedLanes.clear();
276 myIntervals.push_back(ri);
277 myIntervals.back().id = (long long)&myIntervals.back();
278 if (!(ri.closed.empty() && ri.closedLanes.empty()) && ri.permissions != SVCAll) {
281 }
282 }
283}
284
285
286// ------------ loading end
287
288
291 bool updateVehicles = false;
292 for (const RerouteInterval& i : myIntervals) {
293 if (i.begin == currentTime && !(i.closed.empty() && i.closedLanes.empty()) && i.permissions != SVCAll) {
294 for (MSEdge* e : i.closed) {
295 for (MSLane* lane : e->getLanes()) {
296 //std::cout << SIMTIME << " closing: intervalID=" << i.id << " lane=" << (*l)->getID() << " prevPerm=" << getVehicleClassNames((*l)->getPermissions()) << " new=" << getVehicleClassNames(i.permissions) << "\n";
297 lane->setPermissions(i.permissions, i.id);
298 }
300 updateVehicles = true;
301 }
302 for (MSLane* lane : i.closedLanes) {
303 lane->setPermissions(i.permissions, i.id);
305 updateVehicles = true;
306 }
309 }
310 if (i.end == currentTime && !(i.closed.empty() && i.closedLanes.empty()) && i.permissions != SVCAll) {
311 for (MSEdge* e : i.closed) {
312 for (MSLane* lane : e->getLanes()) {
313 lane->resetPermissions(i.id);
314 //std::cout << SIMTIME << " opening: intervalID=" << i.id << " lane=" << (*l)->getID() << " restore prevPerm=" << getVehicleClassNames((*l)->getPermissions()) << "\n";
315 }
317 updateVehicles = true;
318 }
319 for (MSLane* lane : i.closedLanes) {
320 lane->resetPermissions(i.id);
322 updateVehicles = true;
323 }
324 }
325 }
326 if (updateVehicles) {
327 // only vehicles on the affected lanes had their bestlanes updated so far
328 for (MSEdge* e : myEdges) {
329 // also updates vehicles
330 e->rebuildAllowedTargets();
331 }
332 }
333 return 0;
334}
335
336
339 for (std::vector<RerouteInterval>::const_iterator i = myIntervals.begin(); i != myIntervals.end(); ++i) {
340 if (i->begin <= time && i->end > time) {
341 if (
342 // destProbReroute
343 i->edgeProbs.getOverallProb() > 0 ||
344 // routeProbReroute
345 i->routeProbs.getOverallProb() > 0 ||
346 // parkingZoneReroute
347 i->parkProbs.getOverallProb() > 0 ||
348 // affected by closingReroute
349 veh.getRoute().containsAnyOf(i->closed) ||
350 // affected by closingLaneReroute
351 veh.getRoute().containsAnyOf(i->closedLanesAffected)) {
352 return &*i;
353 }
354 }
355 }
356 return nullptr;
357}
358
359
362 for (std::vector<RerouteInterval>::const_iterator i = myIntervals.begin(); i != myIntervals.end(); ++i) {
363 if (i->begin <= time && i->end > time) {
364 if (i->parkProbs.getOverallProb() != 0 || i->edgeProbs.getOverallProb() != 0 || i->routeProbs.getOverallProb() != 0 || !i->closed.empty()) {
365 return &*i;
366 }
367 }
368 }
369 return nullptr;
370}
371
372
373bool
375 double /*newPos*/, double /*newSpeed*/) {
377}
378
379
380bool
382 MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
383 return reason == NOTIFICATION_LANE_CHANGE;
384}
385
386
387bool
389 if (!tObject.isVehicle()) {
390 return false;
391 }
392 SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
393 if (!vehicleApplies(veh)) {
394 return false;
395 }
396 // check whether the vehicle shall be rerouted
398 const MSTriggeredRerouter::RerouteInterval* rerouteDef = getCurrentReroute(time, veh);
399 if (rerouteDef == nullptr) {
400 return true; // an active interval could appear later
401 }
402 const double prob = myAmInUserMode ? myUserProbability : myProbability;
403 if (prob < 1 && RandHelper::rand(veh.getRNG()) > prob) {
404 return false; // XXX another interval could appear later but we would have to track whether the current interval was already tried
405 }
407 return true; // waiting time may be reached later
408 }
409 if (reason == NOTIFICATION_LANE_CHANGE) {
410 return false;
411 }
412 // if we have a closingLaneReroute, only vehicles with a rerouting device can profit from rerouting (otherwise, edge weights will not reflect local jamming)
413 const bool hasReroutingDevice = veh.getDevice(typeid(MSDevice_Routing)) != nullptr;
414 if (rerouteDef->closedLanes.size() > 0 && !hasReroutingDevice) {
415 return true; // an active interval could appear later
416 }
417 // get vehicle params
418 const MSRoute& route = veh.getRoute();
419 const MSEdge* lastEdge = route.getLastEdge();
420#ifdef DEBUG_REROUTER
421 if (DEBUGCOND) {
422 std::cout << SIMTIME << " veh=" << veh.getID() << " check rerouter " << getID() << " lane=" << Named::getIDSecure(veh.getLane()) << " edge=" << veh.getEdge()->getID() << " finalEdge=" << lastEdge->getID() << " arrivalPos=" << veh.getArrivalPos() << "\n";
423 }
424#endif
425
426 if (rerouteDef->parkProbs.getOverallProb() > 0) {
427#ifdef HAVE_FOX
428 ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
429#endif
430 bool newDestination = false;
431 ConstMSEdgeVector newRoute;
432 MSParkingArea* newParkingArea = rerouteParkingArea(rerouteDef, veh, newDestination, newRoute);
433 if (newParkingArea != nullptr) {
434 // adapt plans of any riders
435 for (MSTransportable* p : veh.getPersons()) {
436 p->rerouteParkingArea(veh.getNextParkingArea(), newParkingArea);
437 }
438
439 if (newDestination) {
440 // update arrival parameters
441 SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
442 *newParameter = veh.getParameter();
444 newParameter->arrivalPos = newParkingArea->getEndLanePosition();
445 veh.replaceParameter(newParameter);
446 }
447
448 SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
449 ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->closed)
450 : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->closed);
451 const double routeCost = router.recomputeCosts(newRoute, &veh, MSNet::getInstance()->getCurrentTimeStep());
452 ConstMSEdgeVector prevEdges(veh.getCurrentRouteEdge(), veh.getRoute().end());
453 const double previousCost = router.recomputeCosts(prevEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
454 const double savings = previousCost - routeCost;
455 hasReroutingDevice
457 : MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
458 //if (getID() == "ego") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
459 // << " prevEdges=" << toString(prevEdges)
460 // << " newEdges=" << toString(edges)
461 // << "\n";
462
463 std::string errorMsg;
464 if (veh.replaceParkingArea(newParkingArea, errorMsg)) {
465 veh.replaceRouteEdges(newRoute, routeCost, savings, getID() + ":" + toString(SUMO_TAG_PARKING_AREA_REROUTE), false, false, false);
466 } else {
467 WRITE_WARNING("Vehicle '" + veh.getID() + "' at rerouter '" + getID()
468 + "' could not reroute to new parkingArea '" + newParkingArea->getID()
469 + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
470 }
471 }
472 return false;
473 }
474
475 // get rerouting params
476 ConstMSRoutePtr newRoute = rerouteDef->routeProbs.getOverallProb() > 0 ? rerouteDef->routeProbs.get() : 0;
477 // we will use the route if given rather than calling our own dijsktra...
478 if (newRoute != nullptr) {
479#ifdef DEBUG_REROUTER
480 if (DEBUGCOND) {
481 std::cout << " replacedRoute from routeDist " << newRoute->getID() << "\n";
482 }
483#endif
484 veh.replaceRoute(newRoute, getID());
485 return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
486 }
487 const MSEdge* newEdge = lastEdge;
488 // ok, try using a new destination
489 double newArrivalPos = -1;
490 const bool destUnreachable = std::find(rerouteDef->closed.begin(), rerouteDef->closed.end(), lastEdge) != rerouteDef->closed.end();
491 bool keepDestination = false;
492 // if we have a closingReroute, only assign new destinations to vehicles which cannot reach their original destination
493 // if we have a closingLaneReroute, no new destinations should be assigned
494 if (rerouteDef->closed.size() == 0 || destUnreachable) {
495 newEdge = rerouteDef->edgeProbs.getOverallProb() > 0 ? rerouteDef->edgeProbs.get() : route.getLastEdge();
496 if (newEdge == &mySpecialDest_terminateRoute) {
497 keepDestination = true;
498 newEdge = veh.getEdge();
499 newArrivalPos = veh.getPositionOnLane(); // instant arrival
500 } else if (newEdge == &mySpecialDest_keepDestination || newEdge == lastEdge) {
501 if (destUnreachable && rerouteDef->permissions == SVCAll) {
502 // if permissions aren't set vehicles will simply drive through
503 // the closing unless terminated. If the permissions are specified, assume that the user wants
504 // vehicles to stand and wait until the closing ends
505 WRITE_WARNINGF(TL("Cannot keep destination edge '%' for vehicle '%' due to closed edges. Terminating route."), lastEdge->getID(), veh.getID());
506 newEdge = veh.getEdge();
507 } else {
508 newEdge = lastEdge;
509 }
510 } else if (newEdge == nullptr) {
511#ifdef DEBUG_REROUTER
512 if (DEBUGCOND) {
513 std::cout << " could not find new edge!\n";
514 }
515#endif
516 assert(false); // this should never happen
517 newEdge = veh.getEdge();
518 }
519 }
520 // we have a new destination, let's replace the vehicle route (if it is affected)
521 if (rerouteDef->closed.size() == 0 || destUnreachable || veh.getRoute().containsAnyOf(rerouteDef->closed)) {
522 ConstMSEdgeVector edges;
523 SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
524 ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->closed)
525 : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->closed);
526 router.compute(veh.getEdge(), newEdge, &veh, MSNet::getInstance()->getCurrentTimeStep(), edges);
527 if (edges.size() == 0 && !keepDestination && rerouteDef->edgeProbs.getOverallProb() > 0) {
528 // destination unreachable due to closed intermediate edges. pick among alternative targets
529 RandomDistributor<MSEdge*> edgeProbs2 = rerouteDef->edgeProbs;
530 edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
531 while (edges.size() == 0 && edgeProbs2.getVals().size() > 0) {
532 newEdge = edgeProbs2.get();
533 edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
534 if (newEdge == &mySpecialDest_terminateRoute) {
535 newEdge = veh.getEdge();
536 newArrivalPos = veh.getPositionOnLane(); // instant arrival
537 }
538 if (newEdge == &mySpecialDest_keepDestination && rerouteDef->permissions != SVCAll) {
539 newEdge = lastEdge;
540 break;
541 }
542 router.compute(
543 veh.getEdge(), newEdge, &veh, MSNet::getInstance()->getCurrentTimeStep(), edges);
544 }
545
546 }
547 const double routeCost = router.recomputeCosts(edges, &veh, MSNet::getInstance()->getCurrentTimeStep());
548 hasReroutingDevice
550 : MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
551 const bool useNewRoute = veh.replaceRouteEdges(edges, routeCost, 0, getID());
552#ifdef DEBUG_REROUTER
553 if (DEBUGCOND) std::cout << " rerouting: newDest=" << newEdge->getID()
554 << " newEdges=" << toString(edges)
555 << " useNewRoute=" << useNewRoute << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
556 << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->closed) << "\n";
557#endif
558 if (useNewRoute && newArrivalPos != -1) {
559 // must be called here because replaceRouteEdges may also set the arrivalPos
560 veh.setArrivalPos(newArrivalPos);
561 }
562 }
563 return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
564}
565
566
567void
569 myAmInUserMode = val;
570}
571
572
573void
575 myUserProbability = prob;
576}
577
578
579bool
581 return myAmInUserMode;
582}
583
584
585double
588}
589
590
591double
593 return myUserProbability;
594}
595
596
597double
598MSTriggeredRerouter::getWeight(SUMOVehicle& veh, const std::string param, const double defaultWeight) const {
599 // get custom vehicle parameter
600 if (veh.getParameter().knowsParameter(param)) {
601 try {
602 return StringUtils::toDouble(veh.getParameter().getParameter(param, "-1"));
603 } catch (...) {
604 WRITE_WARNINGF(TL("Invalid value '%' for vehicle parameter '%'"), veh.getParameter().getParameter(param, "-1"), param);
605 }
606 } else {
607 // get custom vType parameter
608 if (veh.getVehicleType().getParameter().knowsParameter(param)) {
609 try {
611 } catch (...) {
612 WRITE_WARNINGF(TL("Invalid value '%' for vType parameter '%'"), veh.getVehicleType().getParameter().getParameter(param, "-1"), param);
613 }
614 }
615 }
616 //WRITE_MESSAGE("Vehicle '" +veh.getID() + "' does not supply vehicle parameter '" + param + "'. Using default of " + toString(defaultWeight) + "\n";
617 return defaultWeight;
618}
619
620
623 SUMOVehicle& veh, bool& newDestination, ConstMSEdgeVector& newRoute) const {
624 // Reroute destination from initial parking area to an alternative parking area
625 // if the following conditions are met:
626 // - next stop target is a parking area
627 // - target is included in the current alternative set
628 // - target is visibly full
629 // Any parking areas that are visibly full at the current location are
630 // committed to parking memory
631
632 MSParkingArea* nearParkArea = nullptr;
633 std::vector<ParkingAreaVisible> parks = rerouteDef->parkProbs.getVals();
634
635 // get vehicle params
636 MSParkingArea* destParkArea = veh.getNextParkingArea();
637 const MSRoute& route = veh.getRoute();
638
639 if (destParkArea == nullptr) {
640 // not driving towards a parkingArea
641 return nullptr;
642 }
643
644 bool destVisible = false;
645 for (auto paVis : parks) {
646 if (paVis.first == destParkArea
647 && (paVis.second
648 // if the vehicle is on the destParkArea edge it is always visible
649 || &(destParkArea->getLane().getEdge()) == veh.getEdge())) {
650 destVisible = true;
651 break;
652 }
653 }
654
655 MSParkingArea* onTheWay = nullptr;
656 const int parkAnywhere = (int)getWeight(veh, "parking.anywhere", -1);
657
658 // check whether we are ready to accept any free parkingArea along the
659 // way to our destination
660 if (parkAnywhere < 0 || parkAnywhere > veh.getNumberParkingReroutes()) {
661 if (!destVisible) {
662 // cannot determine destination occupancy, only register visibly full
663 for (const ParkingAreaVisible& pav : parks) {
664 if (pav.second && pav.first->getLastStepOccupancy() == pav.first->getCapacity()) {
665 veh.rememberBlockedParkingArea(pav.first, &pav.first->getLane().getEdge() == veh.getEdge());
666 }
667 }
668#ifdef DEBUG_PARKING
669 if (DEBUGCOND) {
670 //std::cout << SIMTIME << " rerouter=" << getID() << " veh=" << veh.getID()
671 // << " dest=" << destParkArea->getID() << " parkAnywhere=" << parkAnywhere << " parkingReroutes=" << veh.getNumberParkingReroutes() << " stay on original route\n";
672 }
673#endif
674 }
675
676 } else {
677 double bestDist = std::numeric_limits<double>::max();
678 const double brakeGap = veh.getBrakeGap(true);
679 for (ParkingAreaVisible& item : parks) {
680 if (item.second) {
681 MSParkingArea* pa = item.first;
682 if (&pa->getLane().getEdge() == veh.getEdge()
683 && pa->getLastStepOccupancy() < pa->getCapacity()) {
684 const double distToStart = pa->getBeginLanePosition() - veh.getPositionOnLane();
685 const double distToEnd = pa->getEndLanePosition() - veh.getPositionOnLane();
686 if (distToEnd > brakeGap) {
687 veh.rememberParkingAreaScore(pa, "dist=" + toString(distToStart));
688 if (distToStart < bestDist) {
689 bestDist = distToStart;
690 onTheWay = pa;
691 }
692 } else {
693 veh.rememberParkingAreaScore(pa, "tooClose");
694 }
695 }
696 }
697 }
698#ifdef DEBUG_PARKING
699 if (DEBUGCOND) {
700 std::cout << SIMTIME << " rerouter=" << getID() << " veh=" << veh.getID()
701 << " dest=" << destParkArea->getID() << " parkAnywhere=" << parkAnywhere << " parkingReroutes=" << veh.getNumberParkingReroutes() << " alongTheWay=" << Named::getIDSecure(onTheWay) << "\n";
702 }
703#endif
704 }
705 if (!destVisible && onTheWay == nullptr) {
706 return nullptr;
707 }
708
709 if (destParkArea->getLastStepOccupancy() == destParkArea->getCapacity() || onTheWay != nullptr) {
710
711 // if the current route ends at the parking area, the new route will
712 // also and at the new area
713 newDestination = (&destParkArea->getLane().getEdge() == route.getLastEdge()
714 && veh.getArrivalPos() >= destParkArea->getBeginLanePosition()
715 && veh.getArrivalPos() <= destParkArea->getEndLanePosition());
716
717#ifdef DEBUG_PARKING
718 if (DEBUGCOND) {
719 std::cout << SIMTIME << " rerouter=" << getID() << " veh=" << veh.getID()
720 << " rerouteParkingArea dest=" << destParkArea->getID()
721 << " onDestEdge=" << (&(destParkArea->getLane().getEdge()) == veh.getEdge())
722 << " newDest=" << newDestination
723 << " onTheWay=" << Named::getIDSecure(onTheWay)
724 << "\n";
725 }
726#endif
727
728 ParkingParamMap_t weights;
729 std::map<MSParkingArea*, ConstMSEdgeVector> newRoutes;
730 std::map<MSParkingArea*, ConstMSEdgeVector> parkApproaches;
731
732 // The probability of choosing this area inside the zone
733 weights["probability"] = getWeight(veh, "parking.probability.weight", 0.0);
734
735 // The capacity of this area
736 weights["capacity"] = getWeight(veh, "parking.capacity.weight", 0.0);
737
738 // The absolute number of free spaces
739 weights["absfreespace"] = getWeight(veh, "parking.absfreespace.weight", 0.0);
740
741 // The relative number of free spaces
742 weights["relfreespace"] = getWeight(veh, "parking.relfreespace.weight", 0.0);
743
744 // The distance to the new parking area
745 weights["distanceto"] = getWeight(veh, "parking.distanceto.weight", getWeight(veh, "parking.distance.weight", 1.0));
746
747 // The time to reach this area
748 weights["timeto"] = getWeight(veh, "parking.timeto.weight", 0.0);
749
750 // The distance from the new parking area
751 weights["distancefrom"] = getWeight(veh, "parking.distancefrom.weight", 0.0);
752
753 // The time to reach the end from this area
754 weights["timefrom"] = getWeight(veh, "parking.timefrom.weight", 0.0);
755
756 // a map stores maximum values to normalize parking values
757 ParkingParamMap_t maxValues;
758
759 maxValues["probability"] = 0.0;
760 maxValues["capacity"] = 0.0;
761 maxValues["absfreespace"] = 0.0;
762 maxValues["relfreespace"] = 0.0;
763 maxValues["distanceto"] = 0.0;
764 maxValues["timeto"] = 0.0;
765 maxValues["distancefrom"] = 0.0;
766 maxValues["timefrom"] = 0.0;
767
768 // a map stores elegible parking areas
769 MSParkingAreaMap_t parkAreas;
770
772
773 const std::vector<double>& probs = rerouteDef->parkProbs.getProbs();
774
775 const double brakeGap = veh.getBrakeGap(true);
776
777 if (onTheWay != nullptr) {
778 // compute new route
779 if (newDestination) {
780 newRoute.push_back(veh.getEdge());
781 } else {
782 bool valid = addParkValues(veh, brakeGap, newDestination, onTheWay, onTheWay->getLastStepOccupancy(), 1, router, parkAreas, newRoutes, parkApproaches, maxValues);
783 if (!valid) {
784 WRITE_WARNINGF(TL("Parkingarea '%' along the way cannot be used by vehicle '%' for unknown reason"), onTheWay->getID(), veh.getID());
785 return nullptr;
786 }
787 newRoute = newRoutes[onTheWay];
788 }
789 return onTheWay;
790 }
791
792 int numAlternatives = 0;
793 std::vector<std::tuple<SUMOTime, MSParkingArea*, int> > blockedTimes;
795 veh.rememberParkingAreaScore(destParkArea, "occupied");
796 veh.rememberBlockedParkingArea(destParkArea, &destParkArea->getLane().getEdge() == veh.getEdge());
797
798 const SUMOTime parkingMemory = TIME2STEPS(getWeight(veh, "parking.memory", 600));
799 const double parkingFrustration = getWeight(veh, "parking.frustration", 100);
800 const double parkingKnowledge = getWeight(veh, "parking.knowledge", 0);
801
802 for (int i = 0; i < (int)parks.size(); ++i) {
803 MSParkingArea* pa = parks[i].first;
804 // alternative occupancy is randomized (but never full) if invisible
805 // current destination must be visible at this point
806 const bool visible = parks[i].second || (pa == destParkArea && destVisible);
807 double paOccupancy = pa->getOccupancy();
808 if (!visible && (parkingKnowledge == 0 || parkingKnowledge < RandHelper::rand(veh.getRNG()))) {
809 const double minOccupancy = MIN2((double)pa->getCapacity() - NUMERICAL_EPS, (veh.getNumberParkingReroutes() * pa->getCapacity() / parkingFrustration));
810 paOccupancy = RandHelper::rand(minOccupancy, (double)pa->getCapacity());
811 // previously visited?
812 SUMOTime blockedTime = veh.sawBlockedParkingArea(pa, false);
813 if (blockedTime >= 0 && SIMSTEP - blockedTime < parkingMemory) {
814 // assume it's still occupied
815 paOccupancy = pa->getCapacity();
816 blockedTimes.push_back(std::make_tuple(blockedTime, pa, i));
817#ifdef DEBUG_PARKING
818 if (DEBUGCOND) {
819 std::cout << " altPA=" << pa->getID() << " was blocked at " << time2string(blockedTime) << "\n";
820 }
821#endif
822 }
823 }
824 if (paOccupancy < pa->getCapacity()) {
825 if (addParkValues(veh, brakeGap, newDestination, pa, paOccupancy, probs[i], router, parkAreas, newRoutes, parkApproaches, maxValues)) {
826 numAlternatives++;
827 }
828 } else if (visible) {
829 // might only be visible now (i.e. because it's on the other
830 // side of the street), so we should remember this for later.
831 veh.rememberBlockedParkingArea(pa, &pa->getLane().getEdge() == veh.getEdge());
832 }
833 }
834 if (numAlternatives == 0) {
835 // use parkingArea with lowest blockedTime
836 std::sort(blockedTimes.begin(), blockedTimes.end(),
837 [](std::tuple<SUMOTime, MSParkingArea*, int> const & t1, std::tuple<SUMOTime, MSParkingArea*, int> const & t2) {
838 if (std::get<0>(t1) < std::get<0>(t2)) {
839 return true;
840 }
841 if (std::get<0>(t1) == std::get<0>(t2)) {
842 if (std::get<1>(t1)->getID() < std::get<1>(t2)->getID()) {
843 return true;
844 }
845 if (std::get<1>(t1)->getID() == std::get<1>(t2)->getID()) {
846 return std::get<2>(t1) < std::get<2>(t2);
847 }
848 }
849 return false;
850 }
851 );
852 for (auto item : blockedTimes) {
853 MSParkingArea* pa = std::get<1>(item);
854 double prob = probs[std::get<2>(item)];
855 // all parking areas are occupied. We have no good basis for
856 // prefering one or the other based on estimated occupancy
857 double paOccupancy = RandHelper::rand((double)pa->getCapacity());
858 if (addParkValues(veh, brakeGap, newDestination, pa, paOccupancy, prob, router, parkAreas, newRoutes, parkApproaches, maxValues)) {
859#ifdef DEBUG_PARKING
860 if (DEBUGCOND) {
861 std::cout << " altPA=" << pa->getID() << " targeting occupied pa based on blockTime " << STEPS2TIME(std::get<0>(item)) << " among " << blockedTimes.size() << " alternatives\n";
862 }
863#endif
864 numAlternatives = 1;
865 break;
866 }
867 //std::cout << " candidate=" << item.second->getID() << " observed=" << time2string(item.first) << "\n";
868 }
869 if (numAlternatives == 0) {
870 // take any random target but prefer that that haven't been visited yet
871 std::vector<std::pair<SUMOTime, MSParkingArea*> > candidates;
872 for (const ParkingAreaVisible& pav : parks) {
873 if (pav.first == destParkArea) {
874 continue;
875 }
876 SUMOTime dummy = veh.sawBlockedParkingArea(pav.first, true);
877 if (dummy < 0) {
878 // randomize among the unvisited
879 dummy = -RandHelper::rand(1000000);
880 }
881 candidates.push_back(std::make_pair(dummy, pav.first));
882 }
883 std::sort(candidates.begin(), candidates.end(),
884 [](std::tuple<SUMOTime, MSParkingArea*> const & t1, std::tuple<SUMOTime, MSParkingArea*> const & t2) {
885 return std::get<0>(t1) < std::get<0>(t2) || (std::get<0>(t1) == std::get<0>(t2) && std::get<1>(t1)->getID() < std::get<1>(t2)->getID());
886 }
887 );
888 for (auto item : candidates) {
889 MSParkingArea* pa = item.second;
890 if (addParkValues(veh, brakeGap, newDestination, pa, 0, 1, router, parkAreas, newRoutes, parkApproaches, maxValues)) {
891#ifdef DEBUG_PARKING
892 if (DEBUGCOND) {
893 std::cout << " altPA=" << pa->getID() << " targeting occupied pa (based on pure randomness) among " << candidates.size() << " alternatives\n";
894 }
895#endif
896 numAlternatives = 1;
897 break;
898 }
899 }
900 }
901 }
902
903 MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
904
905#ifdef DEBUG_PARKING
906 if (DEBUGCOND) {
907 std::cout << " maxValues=" << joinToString(maxValues, " ", ":") << "\n";
908 }
909#endif
910
911 // minimum cost to get the parking area
912 double minParkingCost = 0.0;
913
914 for (MSParkingAreaMap_t::iterator it = parkAreas.begin(); it != parkAreas.end(); ++it) {
915 // get the parking values
916 ParkingParamMap_t parkValues = it->second;
917
918 if (weights["probability"] > 0 && maxValues["probability"] > 0.0) {
919 // random search should not drive past a usable parking area
920 bool dominated = false;
921 double endPos = it->first->getEndLanePosition();
922 const ConstMSEdgeVector& to1 = parkApproaches[it->first];
923 assert(to1.size() > 0);
924 for (auto altPa : parkAreas) {
925 if (altPa.first == it->first) {
926 continue;
927 }
928 const ConstMSEdgeVector& to2 = parkApproaches[altPa.first];
929 assert(to2.size() > 0);
930 if (to1.size() > to2.size()) {
931 if (std::equal(to2.begin(), to2.end(), to1.begin())) {
932 // other target lies on the route to the current candidate
933 dominated = true;
934 //std::cout << SIMTIME << " rrP veh=" << veh.getID() << " full=" << destParkArea->getID() << " cand=" << it->first->getID() << " onTheWay=" << altPa.first->getID() << "\n";
935 break;
936 }
937 } else if (to1 == to2 && endPos > altPa.first->getEndLanePosition()) {
938 // other target is on the same edge but ahead of the current candidate
939 dominated = true;
940 //std::cout << SIMTIME << " rrP veh=" << veh.getID() << " full=" << destParkArea->getID() << " cand=" << it->first->getID() << " sameEdge=" << altPa.first->getID() << "\n";
941 break;
942 }
943 }
944 double prob = 0;
945 if (!dominated) {
946 prob = RandHelper::rand(parkValues["probability"], veh.getRNG());
947 parkValues["probability"] = 1.0 - prob / maxValues["probability"];
948 } else {
949 // worst probability score
950 parkValues["probability"] = 1.0;
951 }
952 } else {
953 // value takes no effect due to weight=0
954 parkValues["probability"] = 0;
955 }
956 // normalizing with maximum values (we want to maximize some parameters then we reverse the value)
957 parkValues["capacity"] = maxValues["capacity"] > 0.0 ? 1.0 - parkValues["capacity"] / maxValues["capacity"] : 0.0;
958 parkValues["absfreespace"] = maxValues["absfreespace"] > 0.0 ? 1.0 - parkValues["absfreespace"] / maxValues["absfreespace"] : 0.0;
959 parkValues["relfreespace"] = maxValues["relfreespace"] > 0.0 ? 1.0 - parkValues["relfreespace"] / maxValues["relfreespace"] : 0.0;
960
961 parkValues["distanceto"] = maxValues["distanceto"] > 0.0 ? parkValues["distanceto"] / maxValues["distanceto"] : 0.0;
962 parkValues["timeto"] = maxValues["timeto"] > 0.0 ? parkValues["timeto"] / maxValues["timeto"] : 0.0;
963
964 parkValues["distancefrom"] = maxValues["distancefrom"] > 0.0 ? parkValues["distancefrom"] / maxValues["distancefrom"] : 0.0;
965 parkValues["timefrom"] = maxValues["timefrom"] > 0.0 ? parkValues["timefrom"] / maxValues["timefrom"] : 0.0;
966
967 // get the parking area cost
968 double parkingCost = 0.0;
969
970 // sum every index with its weight
971 for (ParkingParamMap_t::iterator pc = parkValues.begin(); pc != parkValues.end(); ++pc) {
972 parkingCost += weights[pc->first] * pc->second;
973 }
974 veh.rememberParkingAreaScore(it->first, toString(parkingCost)
975 //+ " rfs=" + toString(parkValues["relfreespace"])
976 //+ " dt=" + toString(parkValues["distanceto"])
977 //+ " p=" + toString(parkValues["probability"])
978 );
979
980 // get the parking area with minimum cost
981 if (nearParkArea == nullptr || parkingCost < minParkingCost) {
982 minParkingCost = parkingCost;
983 nearParkArea = it->first;
984 newRoute = newRoutes[nearParkArea];
985 }
986
987#ifdef DEBUG_PARKING
988 if (DEBUGCOND) {
989 std::cout << " altPA=" << it->first->getID() << " score=" << parkingCost << " vals=" << joinToString(parkValues, " ", ":") << "\n";
990 }
991#endif
992 }
994 } else {
995#ifdef DEBUG_PARKING
996 if (DEBUGCOND) {
997 std::cout << SIMTIME << " rerouter=" << getID() << " veh=" << veh.getID() << " rerouteParkingArea dest=" << destParkArea->getID() << " sufficient space\n";
998 }
999#endif
1000 }
1001
1002#ifdef DEBUG_PARKING
1003 if (DEBUGCOND) {
1004 std::cout << " parkingResult=" << Named::getIDSecure(nearParkArea) << "\n";
1005 }
1006#endif
1007
1008 return nearParkArea;
1009}
1010
1011
1012bool
1013MSTriggeredRerouter::addParkValues(SUMOVehicle& veh, double brakeGap, bool newDestination,
1014 MSParkingArea* pa, double paOccupancy, double prob,
1016 MSParkingAreaMap_t& parkAreas,
1017 std::map<MSParkingArea*, ConstMSEdgeVector>& newRoutes,
1018 std::map<MSParkingArea*, ConstMSEdgeVector>& parkApproaches,
1019 ParkingParamMap_t& maxValues) const {
1020 // a map stores the parking values
1021 ParkingParamMap_t parkValues;
1022
1023 const MSRoute& route = veh.getRoute();
1024 const RGBColor& c = route.getColor();
1025 const MSEdge* parkEdge = &(pa->getLane().getEdge());
1026
1027 const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
1028
1029 // Compute the route from the current edge to the parking area edge
1030 ConstMSEdgeVector edgesToPark;
1031 const double parkPos = pa->getLastFreePos(veh);
1032 const MSEdge* rerouteOrigin = *veh.getRerouteOrigin();
1033 router.compute(rerouteOrigin, veh.getPositionOnLane(), parkEdge, parkPos, &veh, MSNet::getInstance()->getCurrentTimeStep(), edgesToPark, true);
1034
1035#ifdef DEBUG_PARKING
1036 if (DEBUGCOND) {
1037 std::cout << " altPA=" << pa->getID() << " vehEdge=" << veh.getEdge()->getID() << " parkEdge " << parkEdge->getID() << " edgesToPark=" << edgesToPark.size() << "\n";
1038 }
1039#endif
1040
1041 if (edgesToPark.size() > 0) {
1042 // Compute the route from the parking area edge to the end of the route
1043 if (rerouteOrigin != veh.getEdge()) {
1044 edgesToPark.insert(edgesToPark.begin(), veh.getEdge());
1045 }
1046 ConstMSEdgeVector edgesFromPark;
1047 parkApproaches[pa] = edgesToPark;
1048
1049 const MSEdge* nextDestination = route.getLastEdge();
1050 double nextPos = veh.getArrivalPos();
1051 int nextDestinationIndex = route.size() - 1;
1052 if (!newDestination) {
1053 std::vector<std::pair<int, double> > stopIndices = veh.getStopIndices();
1054 if (stopIndices.size() > 1) {
1055 nextDestinationIndex = stopIndices[1].first;
1056 nextDestination = route.getEdges()[nextDestinationIndex];
1057 nextPos = stopIndices[1].second;
1058
1059 }
1060 router.compute(parkEdge, parkPos, nextDestination, nextPos, &veh, MSNet::getInstance()->getCurrentTimeStep(), edgesFromPark, true);
1061 }
1062#ifdef DEBUG_PARKING
1063 if (DEBUGCOND) {
1064 //std::cout << " altPA=" << pa->getID() << " parkEdge=" << parkEdge->getID() << " nextDest=" << nextDestination->getID() << " edgesFromPark=" << edgesFromPark.size() << "\n";
1065 }
1066#endif
1067
1068 if (edgesFromPark.size() > 0 || newDestination) {
1069
1070 parkValues["probability"] = prob;
1071
1072 if (parkValues["probability"] > maxValues["probability"]) {
1073 maxValues["probability"] = parkValues["probability"];
1074 }
1075
1076 parkValues["capacity"] = (double)(pa->getCapacity());
1077 parkValues["absfreespace"] = (double)(pa->getCapacity() - paOccupancy);
1078 // if capacity = 0 then absfreespace and relfreespace are also 0
1079 parkValues["relfreespace"] = parkValues["absfreespace"] / MAX2(1.0, parkValues["capacity"]);
1080
1081 if (parkValues["capacity"] > maxValues["capacity"]) {
1082 maxValues["capacity"] = parkValues["capacity"];
1083 }
1084
1085 if (parkValues["absfreespace"] > maxValues["absfreespace"]) {
1086 maxValues["absfreespace"] = parkValues["absfreespace"];
1087 }
1088
1089 if (parkValues["relfreespace"] > maxValues["relfreespace"]) {
1090 maxValues["relfreespace"] = parkValues["relfreespace"];
1091 }
1092
1093 MSRoute routeToPark(route.getID() + "!topark#1", edgesToPark, false,
1094 &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), route.getStops());
1095
1096 // The distance from the current edge to the new parking area
1097 double toPos = pa->getBeginLanePosition();
1098 if (&pa->getLane().getEdge() == veh.getEdge()) {
1099 toPos = MAX2(veh.getPositionOnLane(), toPos);
1100 }
1101 parkValues["distanceto"] = routeToPark.getDistanceBetween(veh.getPositionOnLane(), toPos,
1102 routeToPark.begin(), routeToPark.end() - 1, includeInternalLengths);
1103
1104 if (parkValues["distanceto"] == std::numeric_limits<double>::max()) {
1105 WRITE_WARNINGF(TL("Invalid distance computation for vehicle '%' to parkingArea '%' at time=%."),
1106 veh.getID(), pa->getID(), time2string(SIMSTEP));
1107 }
1108 const double endPos = pa->getOccupancy() == pa->getCapacity()
1109 ? pa->getLastFreePos(veh, veh.getPositionOnLane() + brakeGap)
1110 : pa->getEndLanePosition();
1111 const double distToEnd = parkValues["distanceto"] - toPos + endPos;
1112#ifdef DEBUG_PARKING
1113 if (DEBUGCOND) {
1114 std::cout << " " << veh.getID() << " candidate=" << pa->getID()
1115 << " distanceTo=" << parkValues["distanceto"]
1116 << " brakeGap=" << brakeGap
1117 << " routeToPark=" << toString(edgesToPark)
1118 << " vehPos=" << veh.getPositionOnLane()
1119 << " begPos=" << pa->getBeginLanePosition()
1120 << " toPos=" << toPos
1121 << " endPos=" << pa->getEndLanePosition()
1122 << " distToEnd=" << distToEnd
1123 << "\n";
1124 }
1125#endif
1126
1127 if (distToEnd < brakeGap) {
1128 veh.rememberParkingAreaScore(pa, "tooClose");
1129#ifdef DEBUG_PARKING
1130 if (DEBUGCOND) {
1131 std::cout << " altPA=" << pa->getID() << " too close to brake (dist=" << distToEnd << " brakeGap=" << brakeGap << "\n";
1132 }
1133#endif
1134 return false;
1135 }
1136
1137 // The time to reach the new parking area
1138 parkValues["timeto"] = router.recomputeCosts(edgesToPark, &veh, MSNet::getInstance()->getCurrentTimeStep());
1139
1140 if (parkValues["distanceto"] > maxValues["distanceto"]) {
1141 maxValues["distanceto"] = parkValues["distanceto"];
1142 }
1143
1144 if (parkValues["timeto"] > maxValues["timeto"]) {
1145 maxValues["timeto"] = parkValues["timeto"];
1146 }
1147
1148 ConstMSEdgeVector newEdges = edgesToPark;
1149
1150 if (newDestination) {
1151 parkValues["distancefrom"] = 0;
1152 parkValues["timefrom"] = 0;
1153 } else {
1154 MSRoute routeFromPark(route.getID() + "!frompark#1", edgesFromPark, false,
1155 &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), route.getStops());
1156 // The distance from the new parking area to the end of the route
1157 parkValues["distancefrom"] = routeFromPark.getDistanceBetween(pa->getBeginLanePosition(), routeFromPark.getLastEdge()->getLength(),
1158 routeFromPark.begin(), routeFromPark.end() - 1, includeInternalLengths);
1159 if (parkValues["distancefrom"] == std::numeric_limits<double>::max()) {
1160 WRITE_WARNINGF(TL("Invalid distance computation for vehicle '%' from parkingArea '%' at time=%."),
1161 veh.getID(), pa->getID(), time2string(SIMSTEP));
1162 }
1163 // The time to reach this area
1164 parkValues["timefrom"] = router.recomputeCosts(edgesFromPark, &veh, SIMSTEP);
1165 newEdges.insert(newEdges.end(), edgesFromPark.begin() + 1, edgesFromPark.end());
1166 newEdges.insert(newEdges.end(), route.begin() + nextDestinationIndex + 1, route.end());
1167 }
1168
1169 if (parkValues["distancefrom"] > maxValues["distancefrom"]) {
1170 maxValues["distancefrom"] = parkValues["distancefrom"];
1171 }
1172
1173 if (parkValues["timefrom"] > maxValues["timefrom"]) {
1174 maxValues["timefrom"] = parkValues["timefrom"];
1175 }
1176
1177 parkAreas[pa] = parkValues;
1178 newRoutes[pa] = newEdges;
1179
1180 return true;
1181 } else {
1182 veh.rememberParkingAreaScore(pa, "destUnreachable");
1183 }
1184 } else {
1185 veh.rememberParkingAreaScore(pa, "unreachable");
1186 }
1187#ifdef DEBUG_PARKING
1188 if (DEBUGCOND) {
1189 std::cout << " altPA=" << pa->getID() << " disconnected\n";
1190 }
1191#endif
1192 // unreachable
1193 return false;
1194}
1195
1196
1197bool
1199 if (myVehicleTypes.empty() || myVehicleTypes.count(veh.getVehicleType().getOriginalID()) > 0) {
1200 return true;
1201 } else {
1203 for (auto vTypeDist : vTypeDists) {
1204 if (myVehicleTypes.count(vTypeDist) > 0) {
1205 return true;
1206 }
1207 }
1208 return false;
1209 }
1210}
1211
1212
1213void
1215 // if a parkingArea is a rerouting target, it should generally have a
1216 // rerouter on it's edge or vehicles will be stuck there once it's full.
1217 // The user should receive a Warning in this case
1218 std::set<MSEdge*> parkingRerouterEdges;
1219 std::map<MSParkingArea*, std::string, ComparatorIdLess> targetedParkingArea; // paID -> targetingRerouter
1220 for (const auto& rr : myInstances) {
1221 bool hasParkingReroute = false;
1222 for (const RerouteInterval& interval : rr.second->myIntervals) {
1223 if (interval.parkProbs.getOverallProb() > 0) {
1224 hasParkingReroute = true;
1225 for (const ParkingAreaVisible& pav : interval.parkProbs.getVals()) {
1226 targetedParkingArea[pav.first] = rr.first;
1227 }
1228 }
1229 }
1230 if (hasParkingReroute) {
1231 parkingRerouterEdges.insert(rr.second->myEdges.begin(), rr.second->myEdges.end());
1232 }
1233 }
1234 for (const auto& item : targetedParkingArea) {
1235 if (parkingRerouterEdges.count(&item.first->getLane().getEdge()) == 0) {
1236 WRITE_WARNINGF(TL("ParkingArea '%' is targeted by rerouter '%' but doesn't have it's own rerouter. This may cause parking search to abort."),
1237 item.first->getID(), item.second);
1238 }
1239 }
1240}
1241/****************************************************************************/
long long int SUMOTime
Definition: GUI.h:36
std::vector< const MSEdge * > ConstMSEdgeVector
Definition: MSEdge.h:74
std::vector< MSEdge * > MSEdgeVector
Definition: MSEdge.h:73
#define DEBUGCOND
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:268
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:267
#define TL(string)
Definition: MsgHandler.h:284
#define TLF(string,...)
Definition: MsgHandler.h:285
std::shared_ptr< const MSRoute > ConstMSRoutePtr
Definition: Route.h:32
std::string time2string(SUMOTime t)
convert SUMOTime to string
Definition: SUMOTime.cpp:68
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition: SUMOTime.cpp:45
#define STEPS2TIME(x)
Definition: SUMOTime.h:54
#define SIMSTEP
Definition: SUMOTime.h:60
#define SUMOTime_MAX
Definition: SUMOTime.h:33
#define SIMTIME
Definition: SUMOTime.h:61
#define TIME2STEPS(x)
Definition: SUMOTime.h:56
const SVCPermissions SVCAll
all VClasses are allowed
SVCPermissions parseVehicleClasses(const std::string &allowedS)
Parses the given definition of allowed vehicle classes into the given containers Deprecated classes g...
@ SVC_AUTHORITY
authorities vehicles
@ GIVEN
The arrival position is given.
@ SUMO_TAG_INTERVAL
an aggreagated-output interval
@ SUMO_TAG_CLOSING_REROUTE
reroute of type closing
@ SUMO_TAG_PARKING_AREA_REROUTE
entry for an alternative parking zone
@ SUMO_TAG_PARKING_AREA
A parking area.
@ SUMO_TAG_ROUTE_PROB_REROUTE
probability of route of a reroute
@ SUMO_TAG_DEST_PROB_REROUTE
probability of destination of a reroute
@ SUMO_TAG_CLOSING_LANE_REROUTE
lane of a reroute of type closing
@ SUMO_ATTR_DISALLOW
@ SUMO_ATTR_ALLOW
@ SUMO_ATTR_BEGIN
weights: time range begin
@ SUMO_ATTR_END
weights: time range end
@ SUMO_ATTR_PROB
@ SUMO_ATTR_ID
@ SUMO_ATTR_VISIBLE
T MIN2(T a, T b)
Definition: StdDefs.h:76
T MAX2(T a, T b)
Definition: StdDefs.h:82
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:283
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
MESegment * getSegmentForEdge(const MSEdge &e, double pos=0)
Get the segment for a given edge at a given position.
Definition: MELoop.cpp:325
A single mesoscopic segment (cell)
Definition: MESegment.h:49
void addDetector(MSMoveReminder *data, int queueIndex=-1)
Adds a data collector for a detector to this segment.
Definition: MESegment.cpp:250
A device that performs vehicle rerouting based on current edge speeds.
A road/street connecting two junctions.
Definition: MSEdge.h:77
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:168
void rebuildAllowedLanes(const bool onInit=false)
Definition: MSEdge.cpp:300
double getLength() const
return the length of the edge
Definition: MSEdge.h:658
static bool dictionary(const std::string &id, MSEdge *edge)
Inserts edge into the static dictionary Returns true if the key id isn't already in the dictionary....
Definition: MSEdge.cpp:945
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
static bool gUseMesoSim
Definition: MSGlobals.h:103
static MELoop * gMesoNet
mesoscopic simulation infrastructure
Definition: MSGlobals.h:109
static int gNumSimThreads
how many threads to use for simulation
Definition: MSGlobals.h:143
static bool gUsingInternalLanes
Information whether the simulation regards internal lanes.
Definition: MSGlobals.h:78
Representation of a lane in the micro simulation.
Definition: MSLane.h:84
void resetPermissions(long long transientID)
Definition: MSLane.cpp:4207
void setPermissions(SVCPermissions permissions, long long transientID)
Sets the permissions to the given value. If a transientID is given, the permissions are recored as te...
Definition: MSLane.cpp:4195
static bool dictionary(const std::string &id, MSLane *lane)
Static (sic!) container methods {.
Definition: MSLane.cpp:2234
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:745
Something on a lane to be noticed about vehicle movement.
Notification
Definition of a vehicle state.
@ NOTIFICATION_LANE_CHANGE
The vehicle changes lanes (micro only)
@ NOTIFICATION_JUNCTION
The vehicle arrived at a junction.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:183
MSEventControl * getBeginOfTimestepEvents()
Returns the event control for events executed at the begin of a time step.
Definition: MSNet.h:471
SUMOAbstractRouter< MSEdge, SUMOVehicle > & getRouterTT(const int rngIndex, const MSEdgeVector &prohibited=MSEdgeVector()) const
Definition: MSNet.cpp:1452
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:320
MSStoppingPlace * getStoppingPlace(const std::string &id, const SumoXMLTag category) const
Returns the named stopping place of the given category.
Definition: MSNet.cpp:1350
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:378
bool hasInternalLinks() const
return whether the network contains internal links
Definition: MSNet.h:776
A lane area vehicles can halt at.
Definition: MSParkingArea.h:58
int getCapacity() const
Returns the area capacity.
double getLastFreePos(const SUMOVehicle &forVehicle, double brakePos=0) const
Returns the last free position on this stop.
int getLastStepOccupancy() const
Returns the area occupancy at the end of the last simulation step.
int getOccupancy() const
Returns the area occupancy.
int size() const
Returns the number of edges to pass.
Definition: MSRoute.cpp:85
const ConstMSEdgeVector & getEdges() const
Definition: MSRoute.h:124
const std::vector< SUMOVehicleParameter::Stop > & getStops() const
Returns the stops.
Definition: MSRoute.cpp:406
MSRouteIterator end() const
Returns the end of the list of edges to pass.
Definition: MSRoute.cpp:79
const MSEdge * getLastEdge() const
returns the destination edge
Definition: MSRoute.cpp:91
double getDistanceBetween(double fromPos, double toPos, const MSEdge *fromEdge, const MSEdge *toEdge, bool includeInternal=true, int routePosition=0) const
Compute the distance between 2 given edges on this route, including the length of internal lanes....
Definition: MSRoute.cpp:307
bool containsAnyOf(const MSEdgeVector &edgelist) const
Definition: MSRoute.cpp:239
static bool dictionary(const std::string &id, ConstMSRoutePtr route)
Adds a route to the dictionary.
Definition: MSRoute.cpp:109
const RGBColor & getColor() const
Returns the color.
Definition: MSRoute.cpp:397
MSRouteIterator begin() const
Returns the begin of the list of edges to pass.
Definition: MSRoute.cpp:73
static SUMOAbstractRouter< MSEdge, SUMOVehicle > & getRouterTT(const int rngIndex, SUMOVehicleClass svc, const MSEdgeVector &prohibited=MSEdgeVector())
return the router instance
double getBeginLanePosition() const
Returns the begin position of this stop.
double getEndLanePosition() const
Returns the end position of this stop.
const MSLane & getLane() const
Returns the lane this stop is located at.
SUMOTime setPermissions(const SUMOTime currentTime)
Sets the edge permission if there are any defined in the closingEdge.
bool notifyEnter(SUMOTrafficObject &veh, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Tries to reroute the vehicle.
bool notifyMove(SUMOTrafficObject &veh, double oldPos, double newPos, double newSpeed)
Triggers rerouting (once) for vehicles that are already on the edge when the rerouter activates.
bool notifyLeave(SUMOTrafficObject &veh, double lastPos, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Removes the reminder.
RandomDistributor< ParkingAreaVisible > myCurrentParkProb
new destinations with probabilities
RandomDistributor< ConstMSRoutePtr > myCurrentRouteProb
new routes with probabilities
double getUserProbability() const
Returns the rerouting probability given by the user.
std::vector< MSLane * > myCurrentClosedLanes
List of closed lanes.
virtual void myStartElement(int element, const SUMOSAXAttributes &attrs)
Called on the opening of a tag;.
MSTriggeredRerouter(const std::string &id, const MSEdgeVector &edges, double prob, bool off, SUMOTime timeThreshold, const std::string &vTypes)
Constructor.
void setUserUsageProbability(double prob)
Sets the probability with which a vehicle is rerouted given by the user.
SVCPermissions myCurrentPermissions
List of permissions for closed edges.
MSParkingArea * rerouteParkingArea(const MSTriggeredRerouter::RerouteInterval *rerouteDef, SUMOVehicle &veh, bool &newDestination, ConstMSEdgeVector &newRoute) const
static MSEdge mySpecialDest_terminateRoute
virtual void myEndElement(int element)
Called when a closing tag occurs.
bool addParkValues(SUMOVehicle &veh, double brakeGap, bool newDestination, MSParkingArea *pa, double paOccupancy, double prob, SUMOAbstractRouter< MSEdge, SUMOVehicle > &router, MSParkingAreaMap_t &parkAreas, std::map< MSParkingArea *, ConstMSEdgeVector > &newRoutes, std::map< MSParkingArea *, ConstMSEdgeVector > &parkApproaches, ParkingParamMap_t &maxValues) const
determine attributes of candiate parking area for scoring
const RerouteInterval * getCurrentReroute(SUMOTime time, SUMOVehicle &veh) const
Returns the rerouting definition valid for the given time and vehicle, 0 if none.
std::pair< MSParkingArea *, bool > ParkingAreaVisible
double myProbability
The probability and the user-given probability.
virtual ~MSTriggeredRerouter()
Destructor.
bool inUserMode() const
Returns whether the user is setting the rerouting probability.
std::map< std::string, double > ParkingParamMap_t
std::set< std::string > myVehicleTypes
The vehicle types to look for (empty means all)
MSEdgeVector myCurrentClosed
List of closed edges.
static void checkParkingRerouteConsistency()
issues warning for incomplete parkingReroute relationships
RandomDistributor< MSEdge * > myCurrentEdgeProb
new destinations with probabilities
static std::map< std::string, MSTriggeredRerouter * > myInstances
bool vehicleApplies(const SUMOVehicle &veh) const
Checks whether the detector measures vehicles of the given type.
double getWeight(SUMOVehicle &veh, const std::string param, const double defaultWeight) const
SUMOTime myCurrentIntervalBegin
The first and the last time steps of the interval.
bool myAmInUserMode
Information whether the current rerouting probability is the user-given.
const MSEdgeVector myEdges
edges where vehicles are notified
static MSEdge mySpecialDest_keepDestination
special destination values
double getProbability() const
Returns the rerouting probability.
std::map< MSParkingArea *, ParkingParamMap_t, ComparatorIdLess > MSParkingAreaMap_t
std::vector< RerouteInterval > myIntervals
List of rerouting definition intervals.
void setUserMode(bool val)
Sets whether the process is currently steered by the user.
const std::set< std::string > getVTypeDistributionMembership(const std::string &id) const
Return the distribution IDs the vehicle type is a member of.
const std::string & getOriginalID() const
Returns the id of the original vehicle type if this is a vehicle specific type, the id otherwise.
const SUMOVTypeParameter & getParameter() const
Base class for objects which have an id.
Definition: Named.h:54
static std::string getIDSecure(const T *obj, const std::string &fallBack="NULL")
get an identifier for Named-like object which may be Null
Definition: Named.h:67
const std::string & getID() const
Returns the id.
Definition: Named.h:74
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:59
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
bool knowsParameter(const std::string &key) const
Returns whether the parameter is known.
static const RGBColor DEFAULT_COLOR
The default color (for vehicle types and vehicles)
Definition: RGBColor.h:199
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
Definition: RandHelper.cpp:94
double getOverallProb() const
Return the sum of the probabilites assigned to the members.
T get(SumoRNG *which=nullptr) const
Draw a sample of the distribution.
bool add(T val, double prob, bool checkDuplicates=true)
Adds a value with an assigned probability to the distribution.
const std::vector< T > & getVals() const
Returns the members of the distribution.
bool remove(T val)
Removes a value with an assigned probability from the distribution.
void clear()
Clears the distribution.
const std::vector< double > & getProbs() const
Returns the probabilities assigned to the members of the distribution.
double recomputeCosts(const std::vector< const E * > &edges, const V *const v, SUMOTime msTime, double *lengthp=nullptr) const
virtual bool compute(const E *from, const E *to, const V *const vehicle, SUMOTime msTime, std::vector< const E * > &into, bool silent=false)=0
Builds the route between the given edges using the minimum effort at the given time The definition of...
Encapsulated SAX-Attributes.
T getOpt(int attr, const char *objectid, bool &ok, T defaultValue=T(), bool report=true) const
Tries to read given attribute assuming it is an int.
SUMOTime getOptSUMOTimeReporting(int attr, const char *objectid, bool &ok, SUMOTime defaultValue, bool report=true) const
Tries to read given attribute assuming it is a SUMOTime.
virtual std::string getStringSecure(int id, const std::string &def) const =0
Returns the string-value of the named (by its enum-value) attribute.
virtual bool hasAttribute(int id) const =0
Returns the information whether the named (by its enum-value) attribute is within the current list.
Representation of a vehicle, person, or container.
virtual SUMOTime getWaitingTime() const =0
virtual bool isVehicle() const
Whether it is a vehicle.
virtual const MSVehicleType & getVehicleType() const =0
Returns the object's "vehicle" type.
virtual const MSLane * getLane() const =0
Returns the lane the object is currently at.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle's parameter (including departure definition)
virtual SUMOVehicleClass getVClass() const =0
Returns the object's access class.
virtual SumoRNG * getRNG() const =0
Returns the associated RNG for this object.
virtual const MSEdge * getEdge() const =0
Returns the edge the object is currently at.
virtual double getPositionOnLane() const =0
Get the object's position along the lane.
Representation of a vehicle.
Definition: SUMOVehicle.h:62
virtual ConstMSEdgeVector::const_iterator getRerouteOrigin() const =0
Returns the starting point for reroutes (usually the current edge)
virtual bool replaceRouteEdges(ConstMSEdgeVector &edges, double cost, double savings, const std::string &info, bool onInit=false, bool check=false, bool removeStops=true, std::string *msgReturn=nullptr)=0
Replaces the current route by the given edges.
virtual void rememberParkingAreaScore(const MSParkingArea *pa, const std::string &score)=0
virtual bool replaceParkingArea(MSParkingArea *parkingArea, std::string &errorMsg)=0
Replaces a stop.
virtual MSParkingArea * getNextParkingArea()=0
virtual SUMOTime getAccumulatedWaitingTime() const =0
virtual int getRNGIndex() const =0
virtual int getNumberParkingReroutes() const =0
virtual const std::vector< MSTransportable * > & getPersons() const =0
retrieve riding persons
virtual double getArrivalPos() const =0
Returns this vehicle's desired arrivalPos for its current route (may change on reroute)
virtual void replaceParameter(const SUMOVehicleParameter *newParameter)=0
Replaces the vehicle's parameter.
virtual void rememberBlockedParkingArea(const MSParkingArea *pa, bool local)=0
virtual SUMOTime sawBlockedParkingArea(const MSParkingArea *pa, bool local) const =0
virtual void resetParkingAreaScores()=0
virtual MSVehicleDevice * getDevice(const std::type_info &type) const =0
Returns a device of the given type if it exists or 0.
virtual double getBrakeGap(bool delayed=false) const =0
get distance for coming to a stop (used for rerouting checks)
virtual std::vector< std::pair< int, double > > getStopIndices() const =0
return list of route indices and stop positions for the remaining stops
virtual void setArrivalPos(double arrivalPos)=0
Sets this vehicle's desired arrivalPos for its current route.
virtual const ConstMSEdgeVector::const_iterator & getCurrentRouteEdge() const =0
Returns an iterator pointing to the current edge in this vehicles route.
virtual void setNumberParkingReroutes(int value)=0
virtual bool replaceRoute(ConstMSRoutePtr route, const std::string &info, bool onInit=false, int offset=0, bool addStops=true, bool removeStops=true, std::string *msgReturn=nullptr)=0
Replaces the current route by the given one.
virtual const MSRoute & getRoute() const =0
Returns the current route.
Structure representing possible vehicle parameter.
double arrivalPos
(optional) The position the vehicle shall arrive on
ArrivalPosDefinition arrivalPosProcedure
Information how the vehicle shall choose the arrival position.
A scoped lock which only triggers on condition.
Definition: ScopedLocker.h:40
std::vector< std::string > getVector()
return vector of strings
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
A wrapper for a Command function.
SUMOTime begin
The begin time these definitions are valid.
RandomDistributor< ConstMSRoutePtr > routeProbs
The distributions of new routes to use.
SUMOTime end
The end time these definitions are valid.
RandomDistributor< MSEdge * > edgeProbs
The distributions of new destinations to use.
MSEdgeVector closedLanesAffected
The list of edges that are affect by closed lanes.
RandomDistributor< ParkingAreaVisible > parkProbs
The distributions of new parking areas to use as destinations.
SVCPermissions permissions
The permissions to use.
MSEdgeVector closed
The list of closed edges.
std::vector< MSLane * > closedLanes
The list of closed lanes.