Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MSTriggeredRerouter.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @author Mirco Sturari
19 : /// @date Mon, 25 July 2005
20 : ///
21 : // Reroutes vehicles passing an edge
22 : /****************************************************************************/
23 : #include <config.h>
24 :
25 : #include <string>
26 : #include <algorithm>
27 : #ifdef HAVE_FOX
28 : #include <utils/common/ScopedLocker.h>
29 : #endif
30 : #include <utils/options/OptionsCont.h>
31 : #include <utils/common/MsgHandler.h>
32 : #include <utils/common/Command.h>
33 : #include <utils/xml/SUMOXMLDefinitions.h>
34 : #include <utils/common/UtilExceptions.h>
35 : #include <utils/common/ToString.h>
36 : #include <utils/common/StringUtils.h>
37 : #include <utils/xml/SUMOSAXHandler.h>
38 : #include <utils/router/DijkstraRouter.h>
39 : #include <utils/common/RandHelper.h>
40 : #include <utils/common/WrappingCommand.h>
41 : #include <microsim/MSEdgeWeightsStorage.h>
42 : #include <microsim/MSLane.h>
43 : #include <microsim/MSVehicle.h>
44 : #include <microsim/MSRoute.h>
45 : #include <microsim/MSEdge.h>
46 : #include <microsim/MSEventControl.h>
47 : #include <microsim/MSNet.h>
48 : #include <microsim/MSVehicleControl.h>
49 : #include <microsim/MSGlobals.h>
50 : #include <microsim/MSParkingArea.h>
51 : #include <microsim/MSStop.h>
52 : #include <microsim/transportables/MSPerson.h>
53 : #include <microsim/devices/MSDevice_Routing.h>
54 : #include <microsim/devices/MSRoutingEngine.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 : // ===========================================================================
69 : MSEdge MSTriggeredRerouter::mySpecialDest_keepDestination("MSTriggeredRerouter_keepDestination", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", -1, 0);
70 : MSEdge MSTriggeredRerouter::mySpecialDest_terminateRoute("MSTriggeredRerouter_terminateRoute", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", -1, 0);
71 : std::map<std::string, MSTriggeredRerouter*> MSTriggeredRerouter::myInstances;
72 :
73 :
74 : // ===========================================================================
75 : // method definitions
76 : // ===========================================================================
77 3296 : MSTriggeredRerouter::MSTriggeredRerouter(const std::string& id,
78 : const MSEdgeVector& edges, double prob, bool off, bool optional,
79 3296 : SUMOTime timeThreshold, const std::string& vTypes, const Position& pos) :
80 : Named(id),
81 : MSMoveReminder(id),
82 3296 : myEdges(edges),
83 3296 : myProbability(prob),
84 3296 : myUserProbability(prob),
85 3296 : myAmInUserMode(false),
86 3296 : myAmOptional(optional),
87 3296 : myPosition(pos),
88 3296 : myTimeThreshold(timeThreshold),
89 6592 : myHaveParkProbs(false) {
90 3296 : myInstances[id] = this;
91 : // build actors
92 7687 : for (const MSEdge* const e : edges) {
93 4391 : if (MSGlobals::gUseMesoSim) {
94 291 : MSGlobals::gMesoNet->getSegmentForEdge(*e)->addDetector(this);
95 : }
96 9513 : for (MSLane* const lane : e->getLanes()) {
97 5122 : lane->addMoveReminder(this);
98 : }
99 : }
100 3296 : if (off) {
101 1 : setUserMode(true);
102 1 : setUserUsageProbability(0);
103 : }
104 6592 : const std::vector<std::string> vt = StringTokenizer(vTypes).getVector();
105 : myVehicleTypes.insert(vt.begin(), vt.end());
106 3296 : }
107 :
108 :
109 5941 : MSTriggeredRerouter::~MSTriggeredRerouter() {
110 : myInstances.erase(getID());
111 12529 : }
112 :
113 :
114 : // ------------ loading begin
115 : void
116 17485 : MSTriggeredRerouter::myStartElement(int element,
117 : const SUMOSAXAttributes& attrs) {
118 17485 : if (element == SUMO_TAG_INTERVAL) {
119 3279 : bool ok = true;
120 3279 : myParsedRerouteInterval = RerouteInterval();
121 3279 : myParsedRerouteInterval.begin = attrs.getOptSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok, -1);
122 3279 : myParsedRerouteInterval.end = attrs.getOptSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok, SUMOTime_MAX);
123 : }
124 17485 : if (element == SUMO_TAG_DEST_PROB_REROUTE) {
125 : // by giving probabilities of new destinations
126 : // get the destination edge
127 688 : std::string dest = attrs.getStringSecure(SUMO_ATTR_ID, "");
128 344 : if (dest == "") {
129 0 : throw ProcessError(TLF("MSTriggeredRerouter %: No destination edge id given.", getID()));
130 : }
131 344 : MSEdge* to = MSEdge::dictionary(dest);
132 344 : if (to == nullptr) {
133 69 : if (dest == "keepDestination") {
134 : to = &mySpecialDest_keepDestination;
135 41 : } else if (dest == "terminateRoute") {
136 : to = &mySpecialDest_terminateRoute;
137 : } else {
138 0 : throw ProcessError("MSTriggeredRerouter " + getID() + ": Destination edge '" + dest + "' is not known.");
139 : }
140 : }
141 : // get the probability to reroute
142 344 : bool ok = true;
143 344 : double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
144 344 : if (!ok) {
145 0 : throw ProcessError();
146 : }
147 344 : if (prob < 0) {
148 0 : throw ProcessError("MSTriggeredRerouter " + getID() + ": Attribute 'probability' for destination '" + dest + "' is negative (must not).");
149 : }
150 : // add
151 344 : myParsedRerouteInterval.edgeProbs.add(to, prob);
152 : }
153 :
154 17485 : if (element == SUMO_TAG_CLOSING_REROUTE) {
155 : // by closing edge
156 885 : const std::string& closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
157 885 : MSEdge* const closed = MSEdge::dictionary(closed_id);
158 885 : if (closed == nullptr) {
159 0 : throw ProcessError("MSTriggeredRerouter " + getID() + ": Edge '" + closed_id + "' to close is not known.");
160 : }
161 885 : myParsedRerouteInterval.closed.push_back(closed);
162 : bool ok;
163 885 : const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
164 885 : const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
165 885 : myParsedRerouteInterval.permissions = parseVehicleClasses(allow, disallow);
166 : }
167 :
168 17485 : if (element == SUMO_TAG_CLOSING_LANE_REROUTE) {
169 : // by closing lane
170 159 : std::string closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
171 159 : MSLane* closed = MSLane::dictionary(closed_id);
172 159 : if (closed == nullptr) {
173 0 : throw ProcessError("MSTriggeredRerouter " + getID() + ": Lane '" + closed_id + "' to close is not known.");
174 : }
175 159 : myParsedRerouteInterval.closedLanes.push_back(closed);
176 : bool ok;
177 159 : if (attrs.hasAttribute(SUMO_ATTR_ALLOW) || attrs.hasAttribute(SUMO_ATTR_DISALLOW)) {
178 83 : const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
179 83 : const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
180 83 : myParsedRerouteInterval.permissions = parseVehicleClasses(allow, disallow);
181 : } else {
182 : // lane closing only makes sense if the lane really receives reduced permissions
183 76 : myParsedRerouteInterval.permissions = SVC_AUTHORITY;
184 : }
185 : }
186 :
187 17485 : if (element == SUMO_TAG_ROUTE_PROB_REROUTE) {
188 : // by explicit rerouting using routes
189 : // check if route exists
190 1732 : std::string routeStr = attrs.getStringSecure(SUMO_ATTR_ID, "");
191 866 : if (routeStr == "") {
192 0 : throw ProcessError(TLF("MSTriggeredRerouter %: No route id given.", getID()));
193 : }
194 866 : ConstMSRoutePtr route = MSRoute::dictionary(routeStr);
195 866 : if (route == nullptr) {
196 0 : throw ProcessError("MSTriggeredRerouter " + getID() + ": Route '" + routeStr + "' does not exist.");
197 : }
198 :
199 : // get the probability to reroute
200 866 : bool ok = true;
201 866 : double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
202 866 : if (!ok) {
203 0 : throw ProcessError();
204 : }
205 866 : if (prob < 0) {
206 0 : throw ProcessError("MSTriggeredRerouter " + getID() + ": Attribute 'probability' for route '" + routeStr + "' is negative (must not).");
207 : }
208 : // add
209 1732 : myParsedRerouteInterval.routeProbs.add(route, prob);
210 : }
211 :
212 17485 : if (element == SUMO_TAG_PARKING_AREA_REROUTE) {
213 23820 : std::string parkingarea = attrs.getStringSecure(SUMO_ATTR_ID, "");
214 11910 : if (parkingarea == "") {
215 0 : throw ProcessError(TLF("MSTriggeredRerouter %: No parking area id given.", getID()));
216 : }
217 11910 : MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(parkingarea, SUMO_TAG_PARKING_AREA));
218 11910 : if (pa == nullptr) {
219 0 : throw ProcessError("MSTriggeredRerouter " + getID() + ": Parking area '" + parkingarea + "' is not known.");
220 : }
221 : // get the probability to reroute
222 11910 : bool ok = true;
223 11910 : const double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
224 11910 : if (!ok) {
225 0 : throw ProcessError();
226 : }
227 11910 : if (prob < 0) {
228 0 : throw ProcessError("MSTriggeredRerouter " + getID() + ": Attribute 'probability' for destination '" + parkingarea + "' is negative (must not).");
229 : }
230 11910 : const bool visible = attrs.getOpt<bool>(SUMO_ATTR_VISIBLE, getID().c_str(), ok, false);
231 : // add
232 11910 : myParsedRerouteInterval.parkProbs.add(std::make_pair(pa, visible), prob);
233 11910 : myHaveParkProbs = true;
234 : }
235 :
236 17485 : if (element == SUMO_TAG_VIA_PROB_REROUTE) {
237 : // by giving probabilities of vias
238 74 : std::string viaID = attrs.getStringSecure(SUMO_ATTR_ID, "");
239 37 : if (viaID == "") {
240 0 : throw ProcessError(TLF("MSTriggeredRerouter %: No via edge id given.", getID()));
241 : }
242 37 : MSEdge* const via = MSEdge::dictionary(viaID);
243 37 : if (via == nullptr) {
244 0 : throw ProcessError("MSTriggeredRerouter " + getID() + ": Via edge '" + viaID + "' is not known.");
245 : }
246 : // get the probability to reroute
247 37 : bool ok = true;
248 37 : double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
249 37 : if (!ok) {
250 0 : throw ProcessError();
251 : }
252 37 : if (prob < 0) {
253 0 : throw ProcessError("MSTriggeredRerouter " + getID() + ": Attribute 'probability' for via '" + viaID + "' is negative (must not).");
254 : }
255 : // add
256 37 : myParsedRerouteInterval.edgeProbs.add(via, prob);
257 37 : myParsedRerouteInterval.isVia = true;
258 : }
259 17485 : }
260 :
261 :
262 : void
263 20781 : MSTriggeredRerouter::myEndElement(int element) {
264 20781 : if (element == SUMO_TAG_INTERVAL) {
265 15186 : for (auto paVi : myParsedRerouteInterval.parkProbs.getVals()) {
266 11907 : paVi.first->setNumAlternatives((int)myParsedRerouteInterval.parkProbs.getVals().size() - 1);
267 : }
268 3279 : if (myParsedRerouteInterval.closedLanes.size() > 0) {
269 : // collect edges that are affect by a closed lane
270 : std::set<MSEdge*> affected;
271 275 : for (const MSLane* const l : myParsedRerouteInterval.closedLanes) {
272 159 : affected.insert(&l->getEdge());
273 : }
274 116 : myParsedRerouteInterval.closedLanesAffected.insert(myParsedRerouteInterval.closedLanesAffected.begin(), affected.begin(), affected.end());
275 : }
276 3279 : const SUMOTime closingBegin = myParsedRerouteInterval.begin;
277 6558 : const SUMOTime simBegin = string2time(OptionsCont::getOptions().getString("begin"));
278 3279 : if (closingBegin < simBegin && myParsedRerouteInterval.end > simBegin) {
279 : // interval started before simulation begin but is still active at
280 : // the start of the simulation
281 262 : myParsedRerouteInterval.begin = simBegin;
282 : }
283 3279 : myIntervals.push_back(myParsedRerouteInterval);
284 3279 : myIntervals.back().id = (long long int)&myIntervals.back();
285 3279 : if (!(myParsedRerouteInterval.closed.empty() && myParsedRerouteInterval.closedLanes.empty()) && myParsedRerouteInterval.permissions != SVCAll) {
286 832 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
287 416 : new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), myParsedRerouteInterval.begin);
288 : }
289 : }
290 20781 : }
291 :
292 :
293 : // ------------ loading end
294 :
295 :
296 : SUMOTime
297 548 : MSTriggeredRerouter::setPermissions(const SUMOTime currentTime) {
298 : bool updateVehicles = false;
299 1138 : for (const RerouteInterval& i : myIntervals) {
300 590 : if (i.begin == currentTime && !(i.closed.empty() && i.closedLanes.empty()) && i.permissions != SVCAll) {
301 896 : for (MSEdge* const e : i.closed) {
302 947 : for (MSLane* lane : e->getLanes()) {
303 : //std::cout << SIMTIME << " closing: intervalID=" << i.id << " lane=" << (*l)->getID() << " prevPerm=" << getVehicleClassNames((*l)->getPermissions()) << " new=" << getVehicleClassNames(i.permissions) << "\n";
304 481 : lane->setPermissions(i.permissions, i.id);
305 : }
306 466 : e->rebuildAllowedLanes();
307 : updateVehicles = true;
308 : }
309 571 : for (MSLane* const lane : i.closedLanes) {
310 141 : lane->setPermissions(i.permissions, i.id);
311 141 : lane->getEdge().rebuildAllowedLanes();
312 : updateVehicles = true;
313 : }
314 860 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
315 430 : new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), i.end);
316 : }
317 590 : if (i.end == currentTime && !(i.closed.empty() && i.closedLanes.empty()) && i.permissions != SVCAll) {
318 274 : for (MSEdge* const e : i.closed) {
319 260 : for (MSLane* lane : e->getLanes()) {
320 132 : lane->resetPermissions(i.id);
321 : //std::cout << SIMTIME << " opening: intervalID=" << i.id << " lane=" << (*l)->getID() << " restore prevPerm=" << getVehicleClassNames((*l)->getPermissions()) << "\n";
322 : }
323 128 : e->rebuildAllowedLanes();
324 : updateVehicles = true;
325 : }
326 256 : for (MSLane* lane : i.closedLanes) {
327 110 : lane->resetPermissions(i.id);
328 110 : lane->getEdge().rebuildAllowedLanes();
329 : updateVehicles = true;
330 : }
331 : }
332 : }
333 548 : if (updateVehicles) {
334 : // only vehicles on the affected lanes had their bestlanes updated so far
335 1107 : for (MSEdge* e : myEdges) {
336 : // also updates vehicles
337 559 : e->rebuildAllowedTargets();
338 : }
339 : }
340 548 : return 0;
341 : }
342 :
343 :
344 : const MSTriggeredRerouter::RerouteInterval*
345 1554297 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time, SUMOTrafficObject& obj) const {
346 2078426 : for (const RerouteInterval& ri : myIntervals) {
347 1219701 : if (ri.begin <= time && ri.end > time) {
348 : if (
349 : // destProbReroute
350 626304 : ri.edgeProbs.getOverallProb() > 0 ||
351 : // routeProbReroute
352 826125 : ri.routeProbs.getOverallProb() > 0 ||
353 : // parkingZoneReroute
354 : ri.parkProbs.getOverallProb() > 0) {
355 629138 : return &ri;
356 : }
357 84412 : if (!ri.closed.empty() || !ri.closedLanesAffected.empty()) {
358 84412 : const std::set<SUMOTrafficObject::NumericalID>& edgeIndices = obj.getUpcomingEdgeIDs();
359 84412 : if (affected(edgeIndices, ri.closed) || affected(edgeIndices, ri.closedLanesAffected)) {
360 : return &ri;
361 : }
362 : }
363 : }
364 : }
365 : return nullptr;
366 : }
367 :
368 :
369 : const MSTriggeredRerouter::RerouteInterval*
370 4948 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time) const {
371 4962 : for (const RerouteInterval& ri : myIntervals) {
372 4948 : if (ri.begin <= time && ri.end > time) {
373 4934 : if (ri.edgeProbs.getOverallProb() != 0 || ri.routeProbs.getOverallProb() != 0 || ri.parkProbs.getOverallProb() != 0
374 4946 : || !ri.closed.empty() || !ri.closedLanesAffected.empty()) {
375 : return &ri;
376 : }
377 : }
378 : }
379 : return nullptr;
380 : }
381 :
382 :
383 : bool
384 656418 : MSTriggeredRerouter::notifyEnter(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
385 656418 : if (myAmOptional) {
386 : return true;
387 : }
388 655918 : return triggerRouting(tObject, reason);
389 : }
390 :
391 :
392 : bool
393 899099 : MSTriggeredRerouter::notifyMove(SUMOTrafficObject& veh, double /*oldPos*/,
394 : double /*newPos*/, double /*newSpeed*/) {
395 899099 : return triggerRouting(veh, NOTIFICATION_JUNCTION);
396 : }
397 :
398 :
399 : bool
400 102379 : MSTriggeredRerouter::notifyLeave(SUMOTrafficObject& /*veh*/, double /*lastPos*/,
401 : MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
402 102379 : return reason == NOTIFICATION_LANE_CHANGE;
403 : }
404 :
405 :
406 : bool
407 1555087 : MSTriggeredRerouter::triggerRouting(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason) {
408 1555087 : if (!applies(tObject)) {
409 : return false;
410 : }
411 : // check whether the vehicle shall be rerouted
412 1554297 : const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
413 1554297 : const MSTriggeredRerouter::RerouteInterval* const rerouteDef = getCurrentReroute(now, tObject);
414 1554297 : if (rerouteDef == nullptr) {
415 : return true; // an active interval could appear later
416 : }
417 695572 : const double prob = myAmInUserMode ? myUserProbability : myProbability;
418 695572 : if (prob < 1 && RandHelper::rand(tObject.getRNG()) > prob) {
419 : return false; // XXX another interval could appear later but we would have to track whether the current interval was already tried
420 : }
421 695283 : if (myTimeThreshold > 0 && MAX2(tObject.getWaitingTime(), tObject.getWaitingTime(true)) < myTimeThreshold) {
422 : return true; // waiting time may be reached later
423 : }
424 688889 : if (reason == NOTIFICATION_LANE_CHANGE) {
425 : return false;
426 : }
427 : // if we have a closingLaneReroute, only vehicles with a rerouting device can profit from rerouting (otherwise, edge weights will not reflect local jamming)
428 670628 : const bool hasReroutingDevice = tObject.getDevice(typeid(MSDevice_Routing)) != nullptr;
429 670628 : if (rerouteDef->closedLanes.size() > 0 && !hasReroutingDevice) {
430 : return true; // an active interval could appear later
431 : }
432 533851 : const MSEdge* lastEdge = tObject.getRerouteDestination();
433 : #ifdef DEBUG_REROUTER
434 : if (DEBUGCOND) {
435 : 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";
436 : }
437 : #endif
438 :
439 533851 : if (rerouteDef->parkProbs.getOverallProb() > 0) {
440 : #ifdef HAVE_FOX
441 22938 : ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
442 : #endif
443 22938 : if (!tObject.isVehicle()) {
444 : return false;
445 : }
446 : SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
447 22883 : bool newDestination = false;
448 : ConstMSEdgeVector newRoute;
449 22883 : MSParkingArea* newParkingArea = rerouteParkingArea(rerouteDef, veh, newDestination, newRoute);
450 22883 : if (newParkingArea != nullptr) {
451 : // adapt plans of any riders
452 10972 : for (MSTransportable* p : veh.getPersons()) {
453 35 : p->rerouteParkingArea(veh.getNextParkingArea(), newParkingArea);
454 : }
455 :
456 10937 : if (newDestination) {
457 : // update arrival parameters
458 236 : SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
459 236 : *newParameter = veh.getParameter();
460 236 : newParameter->arrivalPosProcedure = ArrivalPosDefinition::GIVEN;
461 236 : newParameter->arrivalPos = newParkingArea->getEndLanePosition();
462 236 : veh.replaceParameter(newParameter);
463 : }
464 :
465 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
466 10772 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->closed)
467 10937 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->closed);
468 10937 : const double routeCost = router.recomputeCosts(newRoute, &veh, MSNet::getInstance()->getCurrentTimeStep());
469 10937 : ConstMSEdgeVector prevEdges(veh.getCurrentRouteEdge(), veh.getRoute().end());
470 10937 : const double previousCost = router.recomputeCosts(prevEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
471 10937 : const double savings = previousCost - routeCost;
472 : hasReroutingDevice
473 21874 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass())
474 11102 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
475 : //if (getID() == "ego") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
476 : // << " prevEdges=" << toString(prevEdges)
477 : // << " newEdges=" << toString(edges)
478 : // << "\n";
479 :
480 : std::string errorMsg;
481 10937 : if (veh.replaceParkingArea(newParkingArea, errorMsg)) {
482 32811 : veh.replaceRouteEdges(newRoute, routeCost, savings, getID() + ":" + toString(SUMO_TAG_PARKING_AREA_REROUTE), false, false, false);
483 : } else {
484 0 : WRITE_WARNING("Vehicle '" + veh.getID() + "' at rerouter '" + getID()
485 : + "' could not reroute to new parkingArea '" + newParkingArea->getID()
486 : + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
487 : }
488 : }
489 : return false;
490 : }
491 :
492 : // get rerouting params
493 510913 : ConstMSRoutePtr newRoute = rerouteDef->routeProbs.getOverallProb() > 0 ? rerouteDef->routeProbs.get() : nullptr;
494 : // we will use the route if given rather than calling our own dijsktra...
495 510913 : if (newRoute != nullptr) {
496 : #ifdef DEBUG_REROUTER
497 : if (DEBUGCOND) {
498 : std::cout << " replacedRoute from routeDist " << newRoute->getID() << "\n";
499 : }
500 : #endif
501 501508 : tObject.replaceRoute(newRoute, getID());
502 501508 : return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
503 : }
504 : const MSEdge* newEdge = lastEdge;
505 : // ok, try using a new destination
506 : double newArrivalPos = -1;
507 9405 : const bool destUnreachable = std::find(rerouteDef->closed.begin(), rerouteDef->closed.end(), lastEdge) != rerouteDef->closed.end();
508 : bool keepDestination = false;
509 : // if we have a closingReroute, only assign new destinations to vehicles which cannot reach their original destination
510 : // if we have a closingLaneReroute, no new destinations should be assigned
511 9405 : if (rerouteDef->closed.empty() || destUnreachable || rerouteDef->isVia) {
512 6535 : newEdge = rerouteDef->edgeProbs.getOverallProb() > 0 ? rerouteDef->edgeProbs.get() : lastEdge;
513 : assert(newEdge != nullptr);
514 6535 : if (newEdge == &mySpecialDest_terminateRoute) {
515 : keepDestination = true;
516 55 : newEdge = tObject.getEdge();
517 55 : newArrivalPos = tObject.getPositionOnLane(); // instant arrival
518 6480 : } else if (newEdge == &mySpecialDest_keepDestination || newEdge == lastEdge) {
519 3588 : if (destUnreachable && rerouteDef->permissions == SVCAll) {
520 : // if permissions aren't set vehicles will simply drive through
521 : // the closing unless terminated. If the permissions are specified, assume that the user wants
522 : // vehicles to stand and wait until the closing ends
523 2889 : WRITE_WARNINGF(TL("Cannot keep destination edge '%' for vehicle '%' due to closed edges. Terminating route."), lastEdge->getID(), tObject.getID());
524 963 : newEdge = tObject.getEdge();
525 : } else {
526 : newEdge = lastEdge;
527 : }
528 : }
529 : }
530 : ConstMSEdgeVector edges;
531 : std::vector<MSTransportableRouter::TripItem> items;
532 : // we have a new destination, let's replace the route (if it is affected)
533 12275 : if (rerouteDef->closed.empty() || destUnreachable || rerouteDef->isVia || affected(tObject.getUpcomingEdgeIDs(), rerouteDef->closed)) {
534 8176 : if (tObject.isVehicle()) {
535 : SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
536 : MSVehicleRouter& router = hasReroutingDevice
537 6706 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->closed)
538 4147 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->closed);
539 6706 : router.compute(veh.getEdge(), newEdge, &veh, now, edges);
540 6706 : if (edges.size() == 0 && !keepDestination && rerouteDef->edgeProbs.getOverallProb() > 0) {
541 : // destination unreachable due to closed intermediate edges. pick among alternative targets
542 82 : RandomDistributor<MSEdge*> edgeProbs2 = rerouteDef->edgeProbs;
543 82 : edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
544 152 : while (edges.size() == 0 && edgeProbs2.getVals().size() > 0) {
545 110 : newEdge = edgeProbs2.get();
546 110 : edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
547 110 : if (newEdge == &mySpecialDest_terminateRoute) {
548 42 : newEdge = veh.getEdge();
549 42 : newArrivalPos = veh.getPositionOnLane(); // instant arrival
550 : }
551 110 : if (newEdge == &mySpecialDest_keepDestination && rerouteDef->permissions != SVCAll) {
552 40 : newEdge = lastEdge;
553 40 : break;
554 : }
555 70 : router.compute(veh.getEdge(), newEdge, &veh, now, edges);
556 : }
557 :
558 82 : }
559 6706 : if (!rerouteDef->isVia) {
560 6706 : const double routeCost = router.recomputeCosts(edges, &veh, now);
561 : hasReroutingDevice
562 6706 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass())
563 10853 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
564 6706 : const bool useNewRoute = veh.replaceRouteEdges(edges, routeCost, 0, getID());
565 : #ifdef DEBUG_REROUTER
566 : if (DEBUGCOND) std::cout << " rerouting: newDest=" << newEdge->getID()
567 : << " newEdges=" << toString(edges)
568 : << " useNewRoute=" << useNewRoute << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
569 : << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->closed) << "\n";
570 : #endif
571 6706 : if (useNewRoute && newArrivalPos != -1) {
572 : // must be called here because replaceRouteEdges may also set the arrivalPos
573 91 : veh.setArrivalPos(newArrivalPos);
574 : }
575 :
576 : }
577 : } else {
578 : // person rerouting here
579 : MSTransportableRouter& router = hasReroutingDevice
580 1470 : ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), rerouteDef->closed)
581 1470 : : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, rerouteDef->closed);
582 4410 : const bool success = router.compute(tObject.getEdge(), newEdge, tObject.getPositionOnLane(), "",
583 1470 : rerouteDef->isVia ? newEdge->getLength() / 2. : tObject.getParameter().arrivalPos, "",
584 1470 : tObject.getMaxSpeed(), nullptr, 0, now, items);
585 1470 : if (!rerouteDef->isVia) {
586 700 : if (success) {
587 1400 : for (const MSTransportableRouter::TripItem& it : items) {
588 700 : if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
589 : edges.pop_back();
590 : }
591 700 : edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
592 700 : if (!edges.empty()) {
593 700 : static_cast<MSPerson&>(tObject).reroute(edges, tObject.getPositionOnLane(), 0, 1);
594 : }
595 : }
596 : } else {
597 : // maybe the pedestrian model still finds a way (JuPedSim)
598 0 : static_cast<MSPerson&>(tObject).reroute({tObject.getEdge(), newEdge}, tObject.getPositionOnLane(), 0, 1);
599 : }
600 : }
601 : }
602 : }
603 : // it was only a via so calculate the remaining part
604 9405 : if (rerouteDef->isVia) {
605 770 : if (tObject.isVehicle()) {
606 : SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
607 0 : if (!edges.empty()) {
608 : edges.pop_back();
609 : }
610 : MSVehicleRouter& router = hasReroutingDevice
611 0 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->closed)
612 0 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->closed);
613 0 : router.compute(newEdge, lastEdge, &veh, now, edges);
614 0 : const double routeCost = router.recomputeCosts(edges, &veh, now);
615 : hasReroutingDevice
616 0 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass())
617 0 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
618 0 : const bool useNewRoute = veh.replaceRouteEdges(edges, routeCost, 0, getID());
619 : #ifdef DEBUG_REROUTER
620 : if (DEBUGCOND) std::cout << " rerouting: newDest=" << newEdge->getID()
621 : << " newEdges=" << toString(edges)
622 : << " useNewRoute=" << useNewRoute << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
623 : << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->closed) << "\n";
624 : #endif
625 0 : if (useNewRoute && newArrivalPos != -1) {
626 : // must be called here because replaceRouteEdges may also set the arrivalPos
627 0 : veh.setArrivalPos(newArrivalPos);
628 : }
629 : } else {
630 : // person rerouting here
631 770 : bool success = !items.empty();
632 770 : if (success) {
633 : MSTransportableRouter& router = hasReroutingDevice
634 770 : ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), rerouteDef->closed)
635 770 : : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, rerouteDef->closed);
636 2310 : success = router.compute(newEdge, lastEdge, newEdge->getLength() / 2., "",
637 770 : tObject.getParameter().arrivalPos, "",
638 770 : tObject.getMaxSpeed(), nullptr, 0, now, items);
639 : }
640 770 : if (success) {
641 2310 : for (const MSTransportableRouter::TripItem& it : items) {
642 1540 : if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
643 : edges.pop_back();
644 : }
645 1540 : edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
646 : }
647 770 : if (!edges.empty()) {
648 770 : static_cast<MSPerson&>(tObject).reroute(edges, tObject.getPositionOnLane(), 0, 1);
649 : }
650 : } else {
651 : // maybe the pedestrian model still finds a way (JuPedSim)
652 0 : static_cast<MSPerson&>(tObject).reroute({tObject.getEdge(), newEdge, lastEdge}, tObject.getPositionOnLane(), 0, 1);
653 : }
654 : }
655 : }
656 : return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
657 9405 : }
658 :
659 :
660 : void
661 1 : MSTriggeredRerouter::setUserMode(bool val) {
662 1 : myAmInUserMode = val;
663 1 : }
664 :
665 :
666 : void
667 1 : MSTriggeredRerouter::setUserUsageProbability(double prob) {
668 1 : myUserProbability = prob;
669 1 : }
670 :
671 :
672 : bool
673 0 : MSTriggeredRerouter::inUserMode() const {
674 0 : return myAmInUserMode;
675 : }
676 :
677 :
678 : double
679 1471 : MSTriggeredRerouter::getProbability() const {
680 1471 : return myAmInUserMode ? myUserProbability : myProbability;
681 : }
682 :
683 :
684 : double
685 0 : MSTriggeredRerouter::getUserProbability() const {
686 0 : return myUserProbability;
687 : }
688 :
689 :
690 : double
691 167394 : MSTriggeredRerouter::getWeight(SUMOVehicle& veh, const std::string param, const double defaultWeight) {
692 : // get custom vehicle parameter
693 167394 : if (veh.getParameter().hasParameter(param)) {
694 : try {
695 40 : return StringUtils::toDouble(veh.getParameter().getParameter(param, "-1"));
696 0 : } catch (...) {
697 0 : WRITE_WARNINGF(TL("Invalid value '%' for vehicle parameter '%'"), veh.getParameter().getParameter(param, "-1"), param);
698 0 : }
699 : } else {
700 : // get custom vType parameter
701 167374 : if (veh.getVehicleType().getParameter().hasParameter(param)) {
702 : try {
703 20594 : return StringUtils::toDouble(veh.getVehicleType().getParameter().getParameter(param, "-1"));
704 0 : } catch (...) {
705 0 : WRITE_WARNINGF(TL("Invalid value '%' for vType parameter '%'"), veh.getVehicleType().getParameter().getParameter(param, "-1"), param);
706 0 : }
707 : }
708 : }
709 : //WRITE_MESSAGE("Vehicle '" +veh.getID() + "' does not supply vehicle parameter '" + param + "'. Using default of " + toString(defaultWeight) + "\n";
710 : return defaultWeight;
711 : }
712 :
713 :
714 : MSParkingArea*
715 22883 : MSTriggeredRerouter::rerouteParkingArea(const MSTriggeredRerouter::RerouteInterval* rerouteDef,
716 : SUMOVehicle& veh, bool& newDestination, ConstMSEdgeVector& newRoute) {
717 : // Reroute destination from initial parking area to an alternative parking area
718 : // if the following conditions are met:
719 : // - next stop target is a parking area
720 : // - target is included in the current alternative set
721 : // - target is visibly full
722 : // Any parking areas that are visibly full at the current location are
723 : // committed to parking memory
724 :
725 22883 : MSParkingArea* nearParkArea = nullptr;
726 22883 : std::vector<ParkingAreaVisible> parks = rerouteDef->parkProbs.getVals();
727 :
728 : // get vehicle params
729 22883 : MSParkingArea* destParkArea = veh.getNextParkingArea();
730 22883 : const MSRoute& route = veh.getRoute();
731 :
732 22883 : if (destParkArea == nullptr) {
733 : // not driving towards a parkingArea
734 : return nullptr;
735 : }
736 : // if the vehicle is on the destParkArea edge it is always visible
737 19686 : bool destVisible = (&destParkArea->getLane().getEdge() == veh.getEdge());
738 :
739 61452 : for (auto paVis : parks) {
740 50607 : if (paVis.first == destParkArea && paVis.second) {
741 : destVisible = true;
742 : break;
743 : }
744 : }
745 :
746 19686 : MSParkingArea* onTheWay = nullptr;
747 19686 : const int parkAnywhere = (int)getWeight(veh, "parking.anywhere", -1);
748 :
749 : // check whether we are ready to accept any free parkingArea along the
750 : // way to our destination
751 19686 : if (parkAnywhere < 0 || parkAnywhere > veh.getNumberParkingReroutes()) {
752 19653 : if (!destVisible) {
753 : // cannot determine destination occupancy, only register visibly full
754 30607 : for (const ParkingAreaVisible& pav : parks) {
755 25914 : if (pav.second && pav.first->getLastStepOccupancy() == pav.first->getCapacity()) {
756 3424 : veh.rememberBlockedParkingArea(pav.first, &pav.first->getLane().getEdge() == veh.getEdge());
757 : }
758 : }
759 : #ifdef DEBUG_PARKING
760 : if (DEBUGCOND) {
761 : //std::cout << SIMTIME << " rerouter=" << getID() << " veh=" << veh.getID()
762 : // << " dest=" << destParkArea->getID() << " parkAnywhere=" << parkAnywhere << " parkingReroutes=" << veh.getNumberParkingReroutes() << " stay on original route\n";
763 : }
764 : #endif
765 : }
766 :
767 : } else {
768 : double bestDist = std::numeric_limits<double>::max();
769 33 : const double brakeGap = veh.getBrakeGap(true);
770 190 : for (ParkingAreaVisible& item : parks) {
771 157 : if (item.second) {
772 62 : MSParkingArea* pa = item.first;
773 62 : if (&pa->getLane().getEdge() == veh.getEdge()
774 62 : && pa->getLastStepOccupancy() < pa->getCapacity()) {
775 24 : const double distToStart = pa->getBeginLanePosition() - veh.getPositionOnLane();
776 24 : const double distToEnd = pa->getEndLanePosition() - veh.getPositionOnLane();
777 24 : if (distToEnd > brakeGap) {
778 38 : veh.rememberParkingAreaScore(pa, "dist=" + toString(distToStart));
779 19 : if (distToStart < bestDist) {
780 : bestDist = distToStart;
781 19 : onTheWay = pa;
782 : }
783 : } else {
784 10 : veh.rememberParkingAreaScore(pa, "tooClose");
785 : }
786 : }
787 : }
788 : }
789 : #ifdef DEBUG_PARKING
790 : if (DEBUGCOND) {
791 : std::cout << SIMTIME << " rerouter=" << getID() << " veh=" << veh.getID()
792 : << " dest=" << destParkArea->getID() << " parkAnywhere=" << parkAnywhere << " parkingReroutes=" << veh.getNumberParkingReroutes() << " alongTheWay=" << Named::getIDSecure(onTheWay) << "\n";
793 : }
794 : #endif
795 : }
796 19686 : if (!destVisible && onTheWay == nullptr) {
797 : return nullptr;
798 : }
799 :
800 14988 : if (destParkArea->getLastStepOccupancy() == destParkArea->getCapacity() || onTheWay != nullptr) {
801 :
802 : // if the current route ends at the parking area, the new route will
803 : // also and at the new area
804 22736 : newDestination = (&destParkArea->getLane().getEdge() == route.getLastEdge()
805 3151 : && veh.getArrivalPos() >= destParkArea->getBeginLanePosition()
806 14519 : && veh.getArrivalPos() <= destParkArea->getEndLanePosition());
807 :
808 : #ifdef DEBUG_PARKING
809 : if (DEBUGCOND) {
810 : std::cout << SIMTIME << " rerouter=" << getID() << " veh=" << veh.getID()
811 : << " rerouteParkingArea dest=" << destParkArea->getID()
812 : << " onDestEdge=" << (&(destParkArea->getLane().getEdge()) == veh.getEdge())
813 : << " newDest=" << newDestination
814 : << " onTheWay=" << Named::getIDSecure(onTheWay)
815 : << "\n";
816 : }
817 : #endif
818 :
819 : ParkingParamMap_t weights;
820 : std::map<MSParkingArea*, ConstMSEdgeVector> newRoutes;
821 : std::map<MSParkingArea*, ConstMSEdgeVector> parkApproaches;
822 :
823 : // The probability of choosing this area inside the zone
824 11368 : weights["probability"] = getWeight(veh, "parking.probability.weight", 0.0);
825 :
826 : // The capacity of this area
827 11368 : weights["capacity"] = getWeight(veh, "parking.capacity.weight", 0.0);
828 :
829 : // The absolute number of free spaces
830 11368 : weights["absfreespace"] = getWeight(veh, "parking.absfreespace.weight", 0.0);
831 :
832 : // The relative number of free spaces
833 11368 : weights["relfreespace"] = getWeight(veh, "parking.relfreespace.weight", 0.0);
834 :
835 : // The distance to the new parking area
836 22736 : weights["distanceto"] = getWeight(veh, "parking.distanceto.weight", getWeight(veh, "parking.distance.weight", 1.0));
837 :
838 : // The time to reach this area
839 11368 : weights["timeto"] = getWeight(veh, "parking.timeto.weight", 0.0);
840 :
841 : // The distance from the new parking area
842 11368 : weights["distancefrom"] = getWeight(veh, "parking.distancefrom.weight", 0.0);
843 :
844 : // The time to reach the end from this area
845 22736 : weights["timefrom"] = getWeight(veh, "parking.timefrom.weight", 0.0);
846 :
847 : // a map stores maximum values to normalize parking values
848 : ParkingParamMap_t maxValues;
849 :
850 11368 : maxValues["probability"] = 0.0;
851 11368 : maxValues["capacity"] = 0.0;
852 11368 : maxValues["absfreespace"] = 0.0;
853 11368 : maxValues["relfreespace"] = 0.0;
854 11368 : maxValues["distanceto"] = 0.0;
855 11368 : maxValues["timeto"] = 0.0;
856 11368 : maxValues["distancefrom"] = 0.0;
857 11368 : maxValues["timefrom"] = 0.0;
858 :
859 : // a map stores elegible parking areas
860 : MSParkingAreaMap_t parkAreas;
861 :
862 11368 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->closed);
863 :
864 : const std::vector<double>& probs = rerouteDef->parkProbs.getProbs();
865 :
866 11368 : const double brakeGap = veh.getBrakeGap(true);
867 :
868 11368 : if (onTheWay != nullptr) {
869 : // compute new route
870 19 : if (newDestination) {
871 0 : newRoute.push_back(veh.getEdge());
872 : } else {
873 19 : bool valid = addParkValues(veh, brakeGap, newDestination, onTheWay, onTheWay->getLastStepOccupancy(), 1, router, parkAreas, newRoutes, parkApproaches, maxValues);
874 19 : if (!valid) {
875 0 : WRITE_WARNINGF(TL("Parkingarea '%' along the way cannot be used by vehicle '%' for unknown reason"), onTheWay->getID(), veh.getID());
876 0 : return nullptr;
877 : }
878 19 : newRoute = newRoutes[onTheWay];
879 : }
880 19 : return onTheWay;
881 : }
882 :
883 : int numAlternatives = 0;
884 : std::vector<std::tuple<SUMOTime, MSParkingArea*, int> > blockedTimes;
885 11349 : veh.resetParkingAreaScores();
886 11349 : veh.rememberParkingAreaScore(destParkArea, "occupied");
887 11349 : veh.rememberBlockedParkingArea(destParkArea, &destParkArea->getLane().getEdge() == veh.getEdge());
888 :
889 11349 : const SUMOTime parkingMemory = TIME2STEPS(getWeight(veh, "parking.memory", 600));
890 11349 : const double parkingFrustration = getWeight(veh, "parking.frustration", 100);
891 11349 : const double parkingKnowledge = getWeight(veh, "parking.knowledge", 0);
892 :
893 60785 : for (int i = 0; i < (int)parks.size(); ++i) {
894 49436 : MSParkingArea* pa = parks[i].first;
895 : // alternative occupancy is randomized (but never full) if invisible
896 : // current destination must be visible at this point
897 49436 : const bool visible = parks[i].second || (pa == destParkArea && destVisible);
898 49436 : double paOccupancy = pa->getOccupancy();
899 49436 : if (!visible && (parkingKnowledge == 0 || parkingKnowledge < RandHelper::rand(veh.getRNG()))) {
900 35858 : const double minOccupancy = MIN2((double)pa->getCapacity() - NUMERICAL_EPS, (veh.getNumberParkingReroutes() * pa->getCapacity() / parkingFrustration));
901 35858 : paOccupancy = RandHelper::rand(minOccupancy, (double)pa->getCapacity());
902 : // previously visited?
903 35858 : SUMOTime blockedTime = veh.sawBlockedParkingArea(pa, false);
904 35858 : if (blockedTime >= 0 && SIMSTEP - blockedTime < parkingMemory) {
905 : // assume it's still occupied
906 18872 : paOccupancy = pa->getCapacity();
907 18872 : blockedTimes.push_back(std::make_tuple(blockedTime, pa, i));
908 : #ifdef DEBUG_PARKING
909 : if (DEBUGCOND) {
910 : std::cout << " altPA=" << pa->getID() << " was blocked at " << time2string(blockedTime) << "\n";
911 : }
912 : #endif
913 : }
914 : }
915 49436 : if (paOccupancy < pa->getCapacity()) {
916 18091 : if (addParkValues(veh, brakeGap, newDestination, pa, paOccupancy, probs[i], router, parkAreas, newRoutes, parkApproaches, maxValues)) {
917 17805 : numAlternatives++;
918 : }
919 31345 : } else if (visible) {
920 : // might only be visible now (i.e. because it's on the other
921 : // side of the street), so we should remember this for later.
922 12294 : veh.rememberBlockedParkingArea(pa, &pa->getLane().getEdge() == veh.getEdge());
923 : }
924 : }
925 11349 : if (numAlternatives == 0) {
926 : // use parkingArea with lowest blockedTime
927 5099 : std::sort(blockedTimes.begin(), blockedTimes.end(),
928 13678 : [](std::tuple<SUMOTime, MSParkingArea*, int> const & t1, std::tuple<SUMOTime, MSParkingArea*, int> const & t2) {
929 13678 : if (std::get<0>(t1) < std::get<0>(t2)) {
930 : return true;
931 : }
932 7710 : if (std::get<0>(t1) == std::get<0>(t2)) {
933 4 : if (std::get<1>(t1)->getID() < std::get<1>(t2)->getID()) {
934 : return true;
935 : }
936 0 : if (std::get<1>(t1)->getID() == std::get<1>(t2)->getID()) {
937 0 : return std::get<2>(t1) < std::get<2>(t2);
938 : }
939 : }
940 : return false;
941 : }
942 : );
943 5099 : for (auto item : blockedTimes) {
944 : MSParkingArea* pa = std::get<1>(item);
945 4492 : double prob = probs[std::get<2>(item)];
946 : // all parking areas are occupied. We have no good basis for
947 : // prefering one or the other based on estimated occupancy
948 4492 : double paOccupancy = RandHelper::rand((double)pa->getCapacity());
949 4492 : if (addParkValues(veh, brakeGap, newDestination, pa, paOccupancy, prob, router, parkAreas, newRoutes, parkApproaches, maxValues)) {
950 : #ifdef DEBUG_PARKING
951 : if (DEBUGCOND) {
952 : std::cout << " altPA=" << pa->getID() << " targeting occupied pa based on blockTime " << STEPS2TIME(std::get<0>(item)) << " among " << blockedTimes.size() << " alternatives\n";
953 : }
954 : #endif
955 : numAlternatives = 1;
956 : break;
957 : }
958 : //std::cout << " candidate=" << item.second->getID() << " observed=" << time2string(item.first) << "\n";
959 : }
960 5099 : if (numAlternatives == 0) {
961 : // take any random target but prefer that that haven't been visited yet
962 : std::vector<std::pair<SUMOTime, MSParkingArea*> > candidates;
963 2397 : for (const ParkingAreaVisible& pav : parks) {
964 1790 : if (pav.first == destParkArea) {
965 : continue;
966 : }
967 1183 : SUMOTime dummy = veh.sawBlockedParkingArea(pav.first, true);
968 1183 : if (dummy < 0) {
969 : // randomize among the unvisited
970 656 : dummy = -RandHelper::rand(1000000);
971 : }
972 1183 : candidates.push_back(std::make_pair(dummy, pav.first));
973 : }
974 607 : std::sort(candidates.begin(), candidates.end(),
975 : [](std::tuple<SUMOTime, MSParkingArea*> const & t1, std::tuple<SUMOTime, MSParkingArea*> const & t2) {
976 2008 : 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());
977 : }
978 : );
979 1038 : for (auto item : candidates) {
980 : MSParkingArea* pa = item.second;
981 607 : if (addParkValues(veh, brakeGap, newDestination, pa, 0, 1, router, parkAreas, newRoutes, parkApproaches, maxValues)) {
982 : #ifdef DEBUG_PARKING
983 : if (DEBUGCOND) {
984 : std::cout << " altPA=" << pa->getID() << " targeting occupied pa (based on pure randomness) among " << candidates.size() << " alternatives\n";
985 : }
986 : #endif
987 : numAlternatives = 1;
988 : break;
989 : }
990 : }
991 : }
992 : }
993 :
994 22698 : MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
995 :
996 : #ifdef DEBUG_PARKING
997 : if (DEBUGCOND) {
998 : std::cout << " maxValues=" << joinToString(maxValues, " ", ":") << "\n";
999 : }
1000 : #endif
1001 :
1002 : // minimum cost to get the parking area
1003 : double minParkingCost = 0.0;
1004 :
1005 33822 : for (MSParkingAreaMap_t::iterator it = parkAreas.begin(); it != parkAreas.end(); ++it) {
1006 : // get the parking values
1007 : ParkingParamMap_t parkValues = it->second;
1008 :
1009 32909 : if (weights["probability"] > 0 && maxValues["probability"] > 0.0) {
1010 : // random search should not drive past a usable parking area
1011 : bool dominated = false;
1012 10436 : double endPos = it->first->getEndLanePosition();
1013 10436 : const ConstMSEdgeVector& to1 = parkApproaches[it->first];
1014 : assert(to1.size() > 0);
1015 33131 : for (auto altPa : parkAreas) {
1016 24559 : if (altPa.first == it->first) {
1017 : continue;
1018 : }
1019 15789 : const ConstMSEdgeVector& to2 = parkApproaches[altPa.first];
1020 : assert(to2.size() > 0);
1021 15789 : if (to1.size() > to2.size()) {
1022 6289 : if (std::equal(to2.begin(), to2.end(), to1.begin())) {
1023 : // other target lies on the route to the current candidate
1024 : dominated = true;
1025 : //std::cout << SIMTIME << " rrP veh=" << veh.getID() << " full=" << destParkArea->getID() << " cand=" << it->first->getID() << " onTheWay=" << altPa.first->getID() << "\n";
1026 : break;
1027 : }
1028 9500 : } else if (to1 == to2 && endPos > altPa.first->getEndLanePosition()) {
1029 : // other target is on the same edge but ahead of the current candidate
1030 : dominated = true;
1031 : //std::cout << SIMTIME << " rrP veh=" << veh.getID() << " full=" << destParkArea->getID() << " cand=" << it->first->getID() << " sameEdge=" << altPa.first->getID() << "\n";
1032 : break;
1033 : }
1034 : }
1035 : double prob = 0;
1036 : if (!dominated) {
1037 8572 : prob = RandHelper::rand(parkValues["probability"], veh.getRNG());
1038 8572 : parkValues["probability"] = 1.0 - prob / maxValues["probability"];
1039 : } else {
1040 : // worst probability score
1041 1864 : parkValues["probability"] = 1.0;
1042 : }
1043 : } else {
1044 : // value takes no effect due to weight=0
1045 12037 : parkValues["probability"] = 0;
1046 : }
1047 : // normalizing with maximum values (we want to maximize some parameters then we reverse the value)
1048 67419 : parkValues["capacity"] = maxValues["capacity"] > 0.0 ? 1.0 - parkValues["capacity"] / maxValues["capacity"] : 0.0;
1049 67419 : parkValues["absfreespace"] = maxValues["absfreespace"] > 0.0 ? 1.0 - parkValues["absfreespace"] / maxValues["absfreespace"] : 0.0;
1050 67419 : parkValues["relfreespace"] = maxValues["relfreespace"] > 0.0 ? 1.0 - parkValues["relfreespace"] / maxValues["relfreespace"] : 0.0;
1051 :
1052 67409 : parkValues["distanceto"] = maxValues["distanceto"] > 0.0 ? parkValues["distanceto"] / maxValues["distanceto"] : 0.0;
1053 67419 : parkValues["timeto"] = maxValues["timeto"] > 0.0 ? parkValues["timeto"] / maxValues["timeto"] : 0.0;
1054 :
1055 65097 : parkValues["distancefrom"] = maxValues["distancefrom"] > 0.0 ? parkValues["distancefrom"] / maxValues["distancefrom"] : 0.0;
1056 65097 : parkValues["timefrom"] = maxValues["timefrom"] > 0.0 ? parkValues["timefrom"] / maxValues["timefrom"] : 0.0;
1057 :
1058 : // get the parking area cost
1059 22473 : double parkingCost = 0.0;
1060 :
1061 : // sum every index with its weight
1062 202257 : for (ParkingParamMap_t::iterator pc = parkValues.begin(); pc != parkValues.end(); ++pc) {
1063 179784 : parkingCost += weights[pc->first] * pc->second;
1064 : }
1065 22473 : veh.rememberParkingAreaScore(it->first, toString(parkingCost)
1066 : //+ " rfs=" + toString(parkValues["relfreespace"])
1067 : //+ " dt=" + toString(parkValues["distanceto"])
1068 : //+ " p=" + toString(parkValues["probability"])
1069 : );
1070 :
1071 : // get the parking area with minimum cost
1072 22473 : if (nearParkArea == nullptr || parkingCost < minParkingCost) {
1073 14370 : minParkingCost = parkingCost;
1074 14370 : nearParkArea = it->first;
1075 14370 : newRoute = newRoutes[nearParkArea];
1076 : }
1077 :
1078 : #ifdef DEBUG_PARKING
1079 : if (DEBUGCOND) {
1080 : std::cout << " altPA=" << it->first->getID() << " score=" << parkingCost << " vals=" << joinToString(parkValues, " ", ":") << "\n";
1081 : }
1082 : #endif
1083 : }
1084 11349 : veh.setNumberParkingReroutes(veh.getNumberParkingReroutes() + 1);
1085 : } else {
1086 : #ifdef DEBUG_PARKING
1087 : if (DEBUGCOND) {
1088 : std::cout << SIMTIME << " rerouter=" << getID() << " veh=" << veh.getID() << " rerouteParkingArea dest=" << destParkArea->getID() << " sufficient space\n";
1089 : }
1090 : #endif
1091 : }
1092 :
1093 : #ifdef DEBUG_PARKING
1094 : if (DEBUGCOND) {
1095 : std::cout << " parkingResult=" << Named::getIDSecure(nearParkArea) << "\n";
1096 : }
1097 : #endif
1098 :
1099 14969 : return nearParkArea;
1100 : }
1101 :
1102 :
1103 : bool
1104 23209 : MSTriggeredRerouter::addParkValues(SUMOVehicle& veh, double brakeGap, bool newDestination,
1105 : MSParkingArea* pa, double paOccupancy, double prob,
1106 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router,
1107 : MSParkingAreaMap_t& parkAreas,
1108 : std::map<MSParkingArea*, ConstMSEdgeVector>& newRoutes,
1109 : std::map<MSParkingArea*, ConstMSEdgeVector>& parkApproaches,
1110 : ParkingParamMap_t& maxValues) {
1111 : // a map stores the parking values
1112 : ParkingParamMap_t parkValues;
1113 :
1114 23209 : const MSRoute& route = veh.getRoute();
1115 23209 : const RGBColor& c = route.getColor();
1116 23209 : const MSEdge* parkEdge = &(pa->getLane().getEdge());
1117 :
1118 23209 : const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
1119 :
1120 : // Compute the route from the current edge to the parking area edge
1121 : ConstMSEdgeVector edgesToPark;
1122 23209 : const double parkPos = pa->getLastFreePos(veh);
1123 23209 : const MSEdge* rerouteOrigin = *veh.getRerouteOrigin();
1124 23209 : router.compute(rerouteOrigin, veh.getPositionOnLane(), parkEdge, parkPos, &veh, MSNet::getInstance()->getCurrentTimeStep(), edgesToPark, true);
1125 :
1126 : #ifdef DEBUG_PARKING
1127 : if (DEBUGCOND) {
1128 : std::cout << " altPA=" << pa->getID() << " vehEdge=" << veh.getEdge()->getID() << " parkEdge " << parkEdge->getID() << " edgesToPark=" << edgesToPark.size() << "\n";
1129 : }
1130 : #endif
1131 :
1132 23209 : if (edgesToPark.size() > 0) {
1133 : // Compute the route from the parking area edge to the end of the route
1134 22737 : if (rerouteOrigin != veh.getEdge()) {
1135 5 : edgesToPark.insert(edgesToPark.begin(), veh.getEdge());
1136 : }
1137 : ConstMSEdgeVector edgesFromPark;
1138 22737 : parkApproaches[pa] = edgesToPark;
1139 :
1140 22737 : const MSEdge* nextDestination = route.getLastEdge();
1141 22737 : double nextPos = veh.getArrivalPos();
1142 22737 : int nextDestinationIndex = route.size() - 1;
1143 22737 : if (!newDestination) {
1144 21576 : std::vector<std::pair<int, double> > stopIndices = veh.getStopIndices();
1145 21576 : if (stopIndices.size() > 1) {
1146 45 : nextDestinationIndex = stopIndices[1].first;
1147 45 : nextDestination = route.getEdges()[nextDestinationIndex];
1148 45 : nextPos = stopIndices[1].second;
1149 :
1150 : }
1151 21576 : router.compute(parkEdge, parkPos, nextDestination, nextPos, &veh, MSNet::getInstance()->getCurrentTimeStep(), edgesFromPark, true);
1152 : }
1153 : #ifdef DEBUG_PARKING
1154 : if (DEBUGCOND) {
1155 : //std::cout << " altPA=" << pa->getID() << " parkEdge=" << parkEdge->getID() << " nextDest=" << nextDestination->getID() << " edgesFromPark=" << edgesFromPark.size() << "\n";
1156 : }
1157 : #endif
1158 :
1159 22737 : if (edgesFromPark.size() > 0 || newDestination) {
1160 :
1161 22737 : parkValues["probability"] = prob;
1162 :
1163 22737 : if (parkValues["probability"] > maxValues["probability"]) {
1164 11132 : maxValues["probability"] = parkValues["probability"];
1165 : }
1166 :
1167 22737 : parkValues["capacity"] = (double)(pa->getCapacity());
1168 22737 : parkValues["absfreespace"] = (double)(pa->getCapacity() - paOccupancy);
1169 : // if capacity = 0 then absfreespace and relfreespace are also 0
1170 45474 : parkValues["relfreespace"] = parkValues["absfreespace"] / MAX2(1.0, parkValues["capacity"]);
1171 :
1172 22737 : if (parkValues["capacity"] > maxValues["capacity"]) {
1173 11132 : maxValues["capacity"] = parkValues["capacity"];
1174 : }
1175 :
1176 22737 : if (parkValues["absfreespace"] > maxValues["absfreespace"]) {
1177 14970 : maxValues["absfreespace"] = parkValues["absfreespace"];
1178 : }
1179 :
1180 22737 : if (parkValues["relfreespace"] > maxValues["relfreespace"]) {
1181 15160 : maxValues["relfreespace"] = parkValues["relfreespace"];
1182 : }
1183 :
1184 22737 : MSRoute routeToPark(route.getID() + "!topark#1", edgesToPark, false,
1185 45474 : &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), route.getStops());
1186 :
1187 : // The distance from the current edge to the new parking area
1188 22737 : double toPos = pa->getBeginLanePosition();
1189 22737 : if (&pa->getLane().getEdge() == veh.getEdge()) {
1190 461 : toPos = MAX2(veh.getPositionOnLane(), toPos);
1191 : }
1192 22737 : parkValues["distanceto"] = routeToPark.getDistanceBetween(veh.getPositionOnLane(), toPos,
1193 22737 : routeToPark.begin(), routeToPark.end() - 1, includeInternalLengths);
1194 :
1195 22737 : if (parkValues["distanceto"] == std::numeric_limits<double>::max()) {
1196 0 : WRITE_WARNINGF(TL("Invalid distance computation for vehicle '%' to parkingArea '%' at time=%."),
1197 : veh.getID(), pa->getID(), time2string(SIMSTEP));
1198 : }
1199 22737 : const double endPos = pa->getOccupancy() == pa->getCapacity()
1200 22737 : ? pa->getLastFreePos(veh, veh.getPositionOnLane() + brakeGap)
1201 8432 : : pa->getEndLanePosition();
1202 22737 : const double distToEnd = parkValues["distanceto"] - toPos + endPos;
1203 : #ifdef DEBUG_PARKING
1204 : if (DEBUGCOND) {
1205 : std::cout << " " << veh.getID() << " candidate=" << pa->getID()
1206 : << " distanceTo=" << parkValues["distanceto"]
1207 : << " brakeGap=" << brakeGap
1208 : << " routeToPark=" << toString(edgesToPark)
1209 : << " vehPos=" << veh.getPositionOnLane()
1210 : << " begPos=" << pa->getBeginLanePosition()
1211 : << " toPos=" << toPos
1212 : << " endPos=" << pa->getEndLanePosition()
1213 : << " distToEnd=" << distToEnd
1214 : << "\n";
1215 : }
1216 : #endif
1217 :
1218 22737 : if (distToEnd < brakeGap) {
1219 245 : veh.rememberParkingAreaScore(pa, "tooClose");
1220 : #ifdef DEBUG_PARKING
1221 : if (DEBUGCOND) {
1222 : std::cout << " altPA=" << pa->getID() << " too close to brake (dist=" << distToEnd << " brakeGap=" << brakeGap << "\n";
1223 : }
1224 : #endif
1225 245 : return false;
1226 : }
1227 :
1228 : // The time to reach the new parking area
1229 22492 : parkValues["timeto"] = router.recomputeCosts(edgesToPark, &veh, MSNet::getInstance()->getCurrentTimeStep());
1230 :
1231 22492 : if (parkValues["distanceto"] > maxValues["distanceto"]) {
1232 17400 : maxValues["distanceto"] = parkValues["distanceto"];
1233 : }
1234 :
1235 22492 : if (parkValues["timeto"] > maxValues["timeto"]) {
1236 17023 : maxValues["timeto"] = parkValues["timeto"];
1237 : }
1238 :
1239 22492 : ConstMSEdgeVector newEdges = edgesToPark;
1240 :
1241 22492 : if (newDestination) {
1242 1161 : parkValues["distancefrom"] = 0;
1243 1161 : parkValues["timefrom"] = 0;
1244 : } else {
1245 21331 : MSRoute routeFromPark(route.getID() + "!frompark#1", edgesFromPark, false,
1246 42662 : &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), route.getStops());
1247 : // The distance from the new parking area to the end of the route
1248 21331 : parkValues["distancefrom"] = routeFromPark.getDistanceBetween(pa->getBeginLanePosition(), routeFromPark.getLastEdge()->getLength(),
1249 21331 : routeFromPark.begin(), routeFromPark.end() - 1, includeInternalLengths);
1250 21331 : if (parkValues["distancefrom"] == std::numeric_limits<double>::max()) {
1251 0 : WRITE_WARNINGF(TL("Invalid distance computation for vehicle '%' from parkingArea '%' at time=%."),
1252 : veh.getID(), pa->getID(), time2string(SIMSTEP));
1253 : }
1254 : // The time to reach this area
1255 21331 : parkValues["timefrom"] = router.recomputeCosts(edgesFromPark, &veh, SIMSTEP);
1256 21331 : newEdges.insert(newEdges.end(), edgesFromPark.begin() + 1, edgesFromPark.end());
1257 21331 : newEdges.insert(newEdges.end(), route.begin() + nextDestinationIndex + 1, route.end());
1258 21331 : }
1259 :
1260 22492 : if (parkValues["distancefrom"] > maxValues["distancefrom"]) {
1261 15900 : maxValues["distancefrom"] = parkValues["distancefrom"];
1262 : }
1263 :
1264 22492 : if (parkValues["timefrom"] > maxValues["timefrom"]) {
1265 15656 : maxValues["timefrom"] = parkValues["timefrom"];
1266 : }
1267 :
1268 22492 : parkAreas[pa] = parkValues;
1269 22492 : newRoutes[pa] = newEdges;
1270 :
1271 : return true;
1272 22737 : } else {
1273 0 : veh.rememberParkingAreaScore(pa, "destUnreachable");
1274 : }
1275 : } else {
1276 944 : veh.rememberParkingAreaScore(pa, "unreachable");
1277 : }
1278 : #ifdef DEBUG_PARKING
1279 : if (DEBUGCOND) {
1280 : std::cout << " altPA=" << pa->getID() << " disconnected\n";
1281 : }
1282 : #endif
1283 : // unreachable
1284 : return false;
1285 : }
1286 :
1287 :
1288 : bool
1289 1555087 : MSTriggeredRerouter::applies(const SUMOTrafficObject& obj) const {
1290 1555087 : if (myVehicleTypes.empty() || myVehicleTypes.count(obj.getVehicleType().getOriginalID()) > 0) {
1291 1554297 : return true;
1292 : } else {
1293 1580 : std::set<std::string> vTypeDists = MSNet::getInstance()->getVehicleControl().getVTypeDistributionMembership(obj.getVehicleType().getOriginalID());
1294 790 : for (auto vTypeDist : vTypeDists) {
1295 : if (myVehicleTypes.count(vTypeDist) > 0) {
1296 : return true;
1297 : }
1298 : }
1299 790 : return false;
1300 : }
1301 : }
1302 :
1303 :
1304 : bool
1305 163864 : MSTriggeredRerouter::affected(const std::set<SUMOTrafficObject::NumericalID>& edgeIndices, const MSEdgeVector& closed) {
1306 183179 : for (const MSEdge* const e : closed) {
1307 87390 : if (edgeIndices.count(e->getNumericalID()) > 0) {
1308 : return true;
1309 : }
1310 : }
1311 : return false;
1312 : }
1313 :
1314 :
1315 : void
1316 20385 : MSTriggeredRerouter::checkParkingRerouteConsistency() {
1317 : // if a parkingArea is a rerouting target, it should generally have a
1318 : // rerouter on its edge or vehicles will be stuck there once it's full.
1319 : // The user should receive a Warning in this case
1320 : std::set<MSEdge*> parkingRerouterEdges;
1321 : std::map<MSParkingArea*, std::string, ComparatorIdLess> targetedParkingArea; // paID -> targetingRerouter
1322 23674 : for (const auto& rr : myInstances) {
1323 : bool hasParkingReroute = false;
1324 6561 : for (const RerouteInterval& interval : rr.second->myIntervals) {
1325 3272 : if (interval.parkProbs.getOverallProb() > 0) {
1326 : hasParkingReroute = true;
1327 13593 : for (const ParkingAreaVisible& pav : interval.parkProbs.getVals()) {
1328 11907 : targetedParkingArea[pav.first] = rr.first;
1329 : }
1330 : }
1331 : }
1332 3289 : if (hasParkingReroute) {
1333 1686 : parkingRerouterEdges.insert(rr.second->myEdges.begin(), rr.second->myEdges.end());
1334 : }
1335 : }
1336 22635 : for (const auto& item : targetedParkingArea) {
1337 2250 : if (parkingRerouterEdges.count(&item.first->getLane().getEdge()) == 0) {
1338 1065 : WRITE_WARNINGF(TL("ParkingArea '%' is targeted by rerouter '%' but doesn't have its own rerouter. This may cause parking search to abort."),
1339 : item.first->getID(), item.second);
1340 : }
1341 : }
1342 20385 : }
1343 :
1344 :
1345 : /****************************************************************************/
|