Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MSTriggeredRerouter.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @author Mirco Sturari
19 : /// @author Mirko Barthauer
20 : /// @date Mon, 25 July 2005
21 : ///
22 : // Reroutes vehicles passing an edge
23 : /****************************************************************************/
24 : #include <config.h>
25 :
26 : #include <string>
27 : #include <algorithm>
28 : #ifdef HAVE_FOX
29 : #include <utils/common/ScopedLocker.h>
30 : #endif
31 : #include <utils/options/OptionsCont.h>
32 : #include <utils/common/MsgHandler.h>
33 : #include <utils/common/Command.h>
34 : #include <utils/xml/SUMOXMLDefinitions.h>
35 : #include <utils/common/UtilExceptions.h>
36 : #include <utils/common/ToString.h>
37 : #include <utils/common/StringUtils.h>
38 : #include <utils/xml/SUMOSAXHandler.h>
39 : #include <utils/router/DijkstraRouter.h>
40 : #include <utils/common/RandHelper.h>
41 : #include <utils/common/WrappingCommand.h>
42 : #include <microsim/MSEdgeWeightsStorage.h>
43 : #include <microsim/MSLane.h>
44 : #include <microsim/MSLink.h>
45 : #include <microsim/MSVehicle.h>
46 : #include <microsim/MSBaseVehicle.h>
47 : #include <microsim/MSRoute.h>
48 : #include <microsim/MSEdge.h>
49 : #include <microsim/MSEventControl.h>
50 : #include <microsim/MSNet.h>
51 : #include <microsim/MSVehicleControl.h>
52 : #include <microsim/MSGlobals.h>
53 : #include <microsim/MSParkingArea.h>
54 : #include <microsim/MSStop.h>
55 : #include <microsim/traffic_lights/MSRailSignal.h>
56 : #include <microsim/traffic_lights/MSRailSignalConstraint.h>
57 : #include <microsim/transportables/MSPerson.h>
58 : #include <microsim/devices/MSDevice_Routing.h>
59 : #include <microsim/devices/MSRoutingEngine.h>
60 : #include "MSTriggeredRerouter.h"
61 :
62 : #include <mesosim/MELoop.h>
63 : #include <mesosim/MESegment.h>
64 :
65 : //#define DEBUG_REROUTER
66 : //#define DEBUG_OVERTAKING
67 : #define DEBUGCOND(veh) (veh.isSelected())
68 : //#define DEBUGCOND(veh) (true)
69 : //#define DEBUGCOND(veh) (veh.getID() == "")
70 :
71 : /// assume that a faster train has more priority and a slower train doesn't matter
72 : #define DEFAULT_PRIO_OVERTAKER 1
73 : #define DEFAULT_PRIO_OVERTAKEN 0.001
74 :
75 : // ===========================================================================
76 : // static member definition
77 : // ===========================================================================
78 : MSEdge MSTriggeredRerouter::mySpecialDest_keepDestination("MSTriggeredRerouter_keepDestination", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", "", -1, 0);
79 : MSEdge MSTriggeredRerouter::mySpecialDest_terminateRoute("MSTriggeredRerouter_terminateRoute", -1, SumoXMLEdgeFunc::UNKNOWN, "", "", "", -1, 0);
80 : const double MSTriggeredRerouter::DEFAULT_MAXDELAY(7200);
81 : std::map<std::string, MSTriggeredRerouter*> MSTriggeredRerouter::myInstances;
82 :
83 :
84 : // ===========================================================================
85 : // method definitions
86 : // ===========================================================================
87 4004 : MSTriggeredRerouter::MSTriggeredRerouter(const std::string& id,
88 : const MSEdgeVector& edges, double prob, bool off, bool optional,
89 4004 : SUMOTime timeThreshold, const std::string& vTypes, const Position& pos, const double radius) :
90 : Named(id),
91 : MSMoveReminder(id),
92 : MSStoppingPlaceRerouter("parking"),
93 4004 : myEdges(edges),
94 4004 : myProbability(prob),
95 4004 : myUserProbability(prob),
96 4004 : myAmInUserMode(false),
97 4004 : myAmOptional(optional),
98 4004 : myPosition(pos),
99 4004 : myRadius(radius),
100 4004 : myTimeThreshold(timeThreshold),
101 12012 : myHaveParkProbs(false) {
102 4004 : myInstances[id] = this;
103 : // build actors
104 9322 : for (const MSEdge* const e : edges) {
105 5318 : if (MSGlobals::gUseMesoSim) {
106 717 : MSGlobals::gMesoNet->getSegmentForEdge(*e)->addDetector(this);
107 : }
108 11289 : for (MSLane* const lane : e->getLanes()) {
109 5971 : lane->addMoveReminder(this);
110 : }
111 : }
112 4004 : if (off) {
113 1 : setUserMode(true);
114 1 : setUserUsageProbability(0);
115 : }
116 8008 : const std::vector<std::string> vt = StringTokenizer(vTypes).getVector();
117 : myVehicleTypes.insert(vt.begin(), vt.end());
118 : if (myPosition == Position::INVALID) {
119 3626 : myPosition = edges.front()->getLanes()[0]->getShape()[0];
120 : }
121 4004 : }
122 :
123 :
124 7272 : MSTriggeredRerouter::~MSTriggeredRerouter() {
125 : myInstances.erase(getID());
126 11272 : }
127 :
128 :
129 : // ------------ loading begin
130 : void
131 19694 : MSTriggeredRerouter::myStartElement(int element,
132 : const SUMOSAXAttributes& attrs) {
133 19694 : if (element == SUMO_TAG_INTERVAL) {
134 3861 : bool ok = true;
135 3861 : myParsedRerouteInterval = RerouteInterval();
136 3861 : myParsedRerouteInterval.begin = attrs.getOptSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok, -1);
137 3861 : myParsedRerouteInterval.end = attrs.getOptSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok, SUMOTime_MAX);
138 3861 : if (myParsedRerouteInterval.begin >= myParsedRerouteInterval.end) {
139 18 : throw ProcessError(TLF("rerouter '%': interval end % is not after begin %.", getID(),
140 : time2string(myParsedRerouteInterval.end),
141 18 : time2string(myParsedRerouteInterval.begin)));
142 : }
143 : }
144 19688 : if (element == SUMO_TAG_DEST_PROB_REROUTE) {
145 : // by giving probabilities of new destinations
146 : // get the destination edge
147 226 : std::string dest = attrs.getStringSecure(SUMO_ATTR_ID, "");
148 226 : if (dest == "") {
149 0 : throw ProcessError(TLF("rerouter '%': destProbReroute has no destination edge id.", getID()));
150 : }
151 226 : MSEdge* to = MSEdge::dictionary(dest);
152 226 : if (to == nullptr) {
153 69 : if (dest == "keepDestination") {
154 : to = &mySpecialDest_keepDestination;
155 41 : } else if (dest == "terminateRoute") {
156 : to = &mySpecialDest_terminateRoute;
157 : } else {
158 0 : throw ProcessError(TLF("rerouter '%': Destination edge '%' is not known.", getID(), dest));
159 : }
160 : }
161 : // get the probability to reroute
162 226 : bool ok = true;
163 226 : double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
164 226 : if (!ok) {
165 0 : throw ProcessError();
166 : }
167 226 : if (prob < 0) {
168 0 : throw ProcessError(TLF("rerouter '%': Attribute 'probability' for destination '%' is negative (must not).", getID(), dest));
169 : }
170 : // add
171 226 : myParsedRerouteInterval.edgeProbs.add(to, prob);
172 : }
173 :
174 19688 : if (element == SUMO_TAG_CLOSING_REROUTE) {
175 : // by closing edge
176 960 : const std::string& closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
177 960 : MSEdge* const closedEdge = MSEdge::dictionary(closed_id);
178 960 : if (closedEdge == nullptr) {
179 0 : throw ProcessError(TLF("rerouter '%': Edge '%' to close is not known.", getID(), closed_id));
180 : }
181 : bool ok;
182 960 : const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
183 960 : const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
184 960 : const SUMOTime until = attrs.getOptSUMOTimeReporting(SUMO_ATTR_UNTIL, nullptr, ok, TIME2STEPS(-1));
185 960 : SVCPermissions permissions = parseVehicleClasses(allow, disallow);
186 960 : myParsedRerouteInterval.closed[closedEdge] = std::make_pair(permissions, STEPS2TIME(until));
187 : }
188 :
189 19688 : if (element == SUMO_TAG_CLOSING_LANE_REROUTE) {
190 : // by closing lane
191 141 : std::string closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
192 141 : MSLane* closedLane = MSLane::dictionary(closed_id);
193 141 : if (closedLane == nullptr) {
194 0 : throw ProcessError(TLF("rerouter '%': Lane '%' to close is not known.", getID(), closed_id));
195 : }
196 : bool ok;
197 : SVCPermissions permissions = SVC_AUTHORITY;
198 141 : if (attrs.hasAttribute(SUMO_ATTR_ALLOW) || attrs.hasAttribute(SUMO_ATTR_DISALLOW)) {
199 68 : const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
200 68 : const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
201 68 : permissions = parseVehicleClasses(allow, disallow);
202 : }
203 141 : myParsedRerouteInterval.closedLanes[closedLane] = permissions;
204 : }
205 :
206 19688 : if (element == SUMO_TAG_ROUTE_PROB_REROUTE) {
207 : // by explicit rerouting using routes
208 : // check if route exists
209 745 : std::string routeStr = attrs.getStringSecure(SUMO_ATTR_ID, "");
210 745 : if (routeStr == "") {
211 0 : throw ProcessError(TLF("rerouter '%': routeProbReroute has no alternative route id.", getID()));
212 : }
213 745 : ConstMSRoutePtr route = MSRoute::dictionary(routeStr);
214 745 : if (route == nullptr) {
215 0 : throw ProcessError(TLF("rerouter '%': Alternative route '%' does not exist.", getID(), routeStr));
216 : }
217 :
218 : // get the probability to reroute
219 745 : bool ok = true;
220 745 : double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
221 745 : if (!ok) {
222 0 : throw ProcessError();
223 : }
224 745 : if (prob < 0) {
225 0 : throw ProcessError(TLF("rerouter '%': Attribute 'probability' for alternative route '%' is negative (must not).", getID(), routeStr));
226 : }
227 : // add
228 1490 : myParsedRerouteInterval.routeProbs.add(route, prob);
229 : }
230 :
231 19688 : if (element == SUMO_TAG_PARKING_AREA_REROUTE) {
232 13584 : std::string parkingarea = attrs.getStringSecure(SUMO_ATTR_ID, "");
233 13584 : if (parkingarea == "") {
234 0 : throw ProcessError(TLF("rerouter '%': parkingAreaReroute requires a parkingArea id.", getID()));
235 : }
236 13584 : MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(parkingarea, SUMO_TAG_PARKING_AREA));
237 13584 : if (pa == nullptr) {
238 0 : throw ProcessError(TLF("rerouter '%': parkingArea '%' is not known.", getID(), parkingarea));
239 : }
240 : // get the probability to reroute
241 13584 : bool ok = true;
242 13584 : const double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
243 13584 : if (!ok) {
244 0 : throw ProcessError();
245 : }
246 13584 : if (prob < 0) {
247 0 : throw ProcessError(TLF("rerouter '%': Attribute 'probability' for parkingArea '%' is negative (must not).", getID(), parkingarea));
248 : }
249 13584 : const bool visible = attrs.getOpt<bool>(SUMO_ATTR_VISIBLE, getID().c_str(), ok, false);
250 : // add
251 13584 : myParsedRerouteInterval.parkProbs.add(std::make_pair(pa, visible), prob);
252 13584 : myHaveParkProbs = true;
253 : }
254 :
255 19688 : if (element == SUMO_TAG_VIA_PROB_REROUTE) {
256 : // by giving probabilities of vias
257 37 : std::string viaID = attrs.getStringSecure(SUMO_ATTR_ID, "");
258 37 : if (viaID == "") {
259 0 : throw ProcessError(TLF("rerouter '%': No via edge id given.", getID()));
260 : }
261 37 : MSEdge* const via = MSEdge::dictionary(viaID);
262 37 : if (via == nullptr) {
263 0 : throw ProcessError(TLF("rerouter '%': Via Edge '%' is not known.", getID(), viaID));
264 : }
265 : // get the probability to reroute
266 37 : bool ok = true;
267 37 : double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
268 37 : if (!ok) {
269 0 : throw ProcessError();
270 : }
271 37 : if (prob < 0) {
272 0 : throw ProcessError(TLF("rerouter '%': Attribute 'probability' for via '%' is negative (must not).", getID(), viaID));
273 : }
274 : // add
275 37 : myParsedRerouteInterval.edgeProbs.add(via, prob);
276 37 : myParsedRerouteInterval.isVia = true;
277 : }
278 19688 : if (element == SUMO_TAG_OVERTAKING_REROUTE) {
279 : // for letting a slow train use a siding to be overtaken by a fast train
280 : OvertakeLocation oloc;
281 99 : bool ok = true;
282 396 : for (const std::string& edgeID : attrs.get<std::vector<std::string> >(SUMO_ATTR_MAIN, getID().c_str(), ok)) {
283 297 : MSEdge* edge = MSEdge::dictionary(edgeID);
284 297 : if (edge == nullptr) {
285 0 : throw InvalidArgument(TLF("The main edge '%' to use within rerouter '%' is not known.", edgeID, getID()));
286 : }
287 297 : oloc.main.push_back(edge);
288 297 : oloc.cMain.push_back(edge);
289 99 : }
290 396 : for (const std::string& edgeID : attrs.get<std::vector<std::string> >(SUMO_ATTR_SIDING, getID().c_str(), ok)) {
291 297 : MSEdge* edge = MSEdge::dictionary(edgeID);
292 297 : if (edge == nullptr) {
293 0 : throw InvalidArgument(TLF("The siding edge '%' to use within rerouter '%' is not known.", edgeID, getID()));
294 : }
295 297 : oloc.siding.push_back(edge);
296 297 : oloc.cSiding.push_back(edge);
297 99 : }
298 99 : oloc.sidingExit = findSignal(oloc.cSiding.begin(), oloc.cSiding.end());
299 99 : if (oloc.sidingExit == nullptr) {
300 0 : throw InvalidArgument(TLF("The siding within rerouter '%' does not have a rail signal.", getID()));
301 : }
302 198 : for (auto it = oloc.cSiding.begin(); it != oloc.cSiding.end(); it++) {
303 198 : oloc.sidingLength += (*it)->getLength();
304 198 : if ((*it)->getToJunction()->getID() == oloc.sidingExit->getID()) {
305 : break;
306 : }
307 : }
308 99 : oloc.minSaving = attrs.getOpt<double>(SUMO_ATTR_MINSAVING, getID().c_str(), ok, 300);
309 99 : const bool hasAlternatives = myParsedRerouteInterval.overtakeLocations.size() > 0;
310 99 : oloc.defer = attrs.getOpt<bool>(SUMO_ATTR_DEFER, getID().c_str(), ok, hasAlternatives);
311 99 : myParsedRerouteInterval.overtakeLocations.push_back(oloc);
312 99 : }
313 19688 : if (element == SUMO_TAG_STATION_REROUTE) {
314 : // for letting a train switch it's stopping place in case of conflict
315 36 : const std::string stopID = attrs.getStringSecure(SUMO_ATTR_ID, "");
316 36 : if (stopID == "") {
317 0 : throw ProcessError(TLF("rerouter '%': stationReroute requires a stopping place id.", getID()));
318 : }
319 36 : MSStoppingPlace* stop = MSNet::getInstance()->getStoppingPlace(stopID);
320 36 : if (stop == nullptr) {
321 0 : throw ProcessError(TLF("rerouter '%': stopping place '%' is not known.", getID(), stopID));
322 : }
323 36 : myParsedRerouteInterval.stopAlternatives.push_back(std::make_pair(stop, true));
324 : }
325 19688 : }
326 :
327 :
328 : void
329 23686 : MSTriggeredRerouter::myEndElement(int element) {
330 23686 : if (element == SUMO_TAG_INTERVAL) {
331 : // precompute permissionsAllowAll
332 : bool allowAll = true;
333 4206 : for (const auto& entry : myParsedRerouteInterval.closed) {
334 789 : allowAll = allowAll && entry.second.first == SVCAll;
335 : if (!allowAll) {
336 : break;
337 : }
338 : }
339 3855 : myParsedRerouteInterval.permissionsAllowAll = allowAll;
340 :
341 17436 : for (auto paVi : myParsedRerouteInterval.parkProbs.getVals()) {
342 13581 : dynamic_cast<MSParkingArea*>(paVi.first)->setNumAlternatives((int)myParsedRerouteInterval.parkProbs.getVals().size() - 1);
343 : }
344 3855 : if (myParsedRerouteInterval.closedLanes.size() > 0) {
345 : // collect edges that are affect by a closed lane
346 : std::set<MSEdge*> affected;
347 226 : for (std::pair<MSLane*, SVCPermissions> settings : myParsedRerouteInterval.closedLanes) {
348 135 : affected.insert(&settings.first->getEdge());
349 : }
350 91 : myParsedRerouteInterval.closedLanesAffected.insert(myParsedRerouteInterval.closedLanesAffected.begin(), affected.begin(), affected.end());
351 : }
352 3855 : const SUMOTime closingBegin = myParsedRerouteInterval.begin;
353 3855 : const SUMOTime simBegin = string2time(OptionsCont::getOptions().getString("begin"));
354 3855 : if (closingBegin < simBegin && myParsedRerouteInterval.end > simBegin) {
355 : // interval started before simulation begin but is still active at
356 : // the start of the simulation
357 415 : myParsedRerouteInterval.begin = simBegin;
358 : }
359 3855 : myIntervals.push_back(myParsedRerouteInterval);
360 3855 : myIntervals.back().id = (long long int)&myIntervals.back();
361 3855 : if (!(myParsedRerouteInterval.closed.empty() && myParsedRerouteInterval.closedLanes.empty())) {
362 1648 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
363 824 : new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), myParsedRerouteInterval.begin);
364 : }
365 : }
366 23686 : }
367 :
368 :
369 : // ------------ loading end
370 :
371 :
372 : SUMOTime
373 987 : MSTriggeredRerouter::setPermissions(const SUMOTime currentTime) {
374 : bool updateVehicles = false;
375 2019 : for (const RerouteInterval& i : myIntervals) {
376 1032 : if (i.begin == currentTime && !(i.closed.empty() && i.closedLanes.empty()) /*&& i.permissions != SVCAll*/) {
377 1763 : for (const auto& settings : i.closed) {
378 1895 : for (MSLane* lane : settings.first->getLanes()) {
379 : //std::cout << SIMTIME << " closing: intervalID=" << i.id << " lane=" << lane->getID() << " prevPerm=" << getVehicleClassNames(lane->getPermissions()) << " new=" << getVehicleClassNames(i.permissions) << "\n";
380 956 : lane->setPermissions(settings.second.first, i.id);
381 : }
382 939 : settings.first->rebuildAllowedLanes();
383 : updateVehicles = true;
384 : }
385 973 : for (std::pair<MSLane*, SVCPermissions> settings : i.closedLanes) {
386 149 : settings.first->setPermissions(settings.second, i.id);
387 149 : settings.first->getEdge().rebuildAllowedLanes();
388 : updateVehicles = true;
389 : }
390 1648 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
391 824 : new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), i.end);
392 : }
393 1032 : if (i.end == currentTime && !(i.closed.empty() && i.closedLanes.empty()) /*&& i.permissions != SVCAll*/) {
394 356 : for (auto settings : i.closed) {
395 335 : for (MSLane* lane : settings.first->getLanes()) {
396 172 : lane->resetPermissions(i.id);
397 : //std::cout << SIMTIME << " opening: intervalID=" << i.id << " lane=" << lane->getID() << " restore prevPerm=" << getVehicleClassNames(lane->getPermissions()) << "\n";
398 : }
399 163 : settings.first->rebuildAllowedLanes();
400 : updateVehicles = true;
401 : }
402 310 : for (std::pair<MSLane*, SVCPermissions> settings : i.closedLanes) {
403 117 : settings.first->resetPermissions(i.id);
404 117 : settings.first->getEdge().rebuildAllowedLanes();
405 : updateVehicles = true;
406 : }
407 : }
408 : }
409 987 : if (updateVehicles) {
410 : // only vehicles on the affected lanes had their bestlanes updated so far
411 1999 : for (MSEdge* e : myEdges) {
412 : // also updates vehicles
413 1012 : e->rebuildAllowedTargets();
414 : }
415 : }
416 987 : return 0;
417 : }
418 :
419 :
420 : const MSTriggeredRerouter::RerouteInterval*
421 1193642 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time, SUMOTrafficObject& obj) const {
422 1703533 : for (const RerouteInterval& ri : myIntervals) {
423 1207723 : if (ri.begin <= time && ri.end > time) {
424 : if (
425 : // destProbReroute
426 712513 : ri.edgeProbs.getOverallProb() > 0 ||
427 : // routeProbReroute
428 176856 : ri.routeProbs.getOverallProb() > 0 ||
429 : // parkingZoneReroute
430 783597 : ri.parkProbs.getOverallProb() > 0 ||
431 : // stationReroute
432 : ri.stopAlternatives.size() > 0) {
433 648011 : return &ri;
434 : }
435 67787 : if (!ri.closed.empty() || !ri.closedLanesAffected.empty() || !ri.overtakeLocations.empty()) {
436 67787 : const std::set<SUMOTrafficObject::NumericalID>& edgeIndices = obj.getUpcomingEdgeIDs();
437 135574 : if (affected(edgeIndices, ri.getClosedEdges())
438 67787 : || affected(edgeIndices, ri.closedLanesAffected)) {
439 49677 : return &ri;
440 : }
441 18110 : for (const OvertakeLocation& oloc : ri.overtakeLocations) {
442 144 : if (affected(edgeIndices, oloc.main)) {
443 : return &ri;
444 : }
445 : }
446 :
447 : }
448 : }
449 : }
450 : return nullptr;
451 : }
452 :
453 :
454 : const MSTriggeredRerouter::RerouteInterval*
455 318093 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time) const {
456 318120 : for (const RerouteInterval& ri : myIntervals) {
457 318093 : if (ri.begin <= time && ri.end > time) {
458 318066 : if (ri.edgeProbs.getOverallProb() != 0 || ri.routeProbs.getOverallProb() != 0 || ri.parkProbs.getOverallProb() != 0
459 318083 : || !ri.closed.empty() || !ri.closedLanesAffected.empty() || !ri.overtakeLocations.empty()) {
460 : return &ri;
461 : }
462 : }
463 : }
464 : return nullptr;
465 : }
466 :
467 :
468 : bool
469 670762 : MSTriggeredRerouter::notifyEnter(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
470 670762 : if (myAmOptional || myRadius != std::numeric_limits<double>::max()) {
471 : return true;
472 : }
473 670622 : return triggerRouting(tObject, reason);
474 : }
475 :
476 :
477 : bool
478 522448 : MSTriggeredRerouter::notifyMove(SUMOTrafficObject& veh, double /*oldPos*/,
479 : double /*newPos*/, double /*newSpeed*/) {
480 522448 : return triggerRouting(veh, NOTIFICATION_JUNCTION);
481 : }
482 :
483 :
484 : bool
485 18946 : MSTriggeredRerouter::notifyLeave(SUMOTrafficObject& /*veh*/, double /*lastPos*/,
486 : MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
487 18946 : return reason == NOTIFICATION_LANE_CHANGE;
488 : }
489 :
490 :
491 : bool
492 1193712 : MSTriggeredRerouter::triggerRouting(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason) {
493 1193712 : if (!applies(tObject)) {
494 : return false;
495 : }
496 1193642 : if (myRadius != std::numeric_limits<double>::max() && tObject.getPosition().distanceTo(myPosition) > myRadius) {
497 0 : return true;
498 : }
499 : // check whether the vehicle shall be rerouted
500 1193642 : const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
501 1193642 : const MSTriggeredRerouter::RerouteInterval* const rerouteDef = getCurrentReroute(now, tObject);
502 1193642 : if (rerouteDef == nullptr) {
503 : return true; // an active interval could appear later
504 : }
505 697832 : const double prob = myAmInUserMode ? myUserProbability : myProbability;
506 697832 : if (prob < 1 && RandHelper::rand(tObject.getRNG()) > prob) {
507 : return false; // XXX another interval could appear later but we would have to track whether the current interval was already tried
508 : }
509 697543 : if (myTimeThreshold > 0 && MAX2(tObject.getWaitingTime(), tObject.getWaitingTime(true)) < myTimeThreshold) {
510 : return true; // waiting time may be reached later
511 : }
512 691096 : if (reason == NOTIFICATION_LANE_CHANGE) {
513 : return false;
514 : }
515 : // if we have a closingLaneReroute, only vehicles with a rerouting device can profit from rerouting (otherwise, edge weights will not reflect local jamming)
516 672946 : const bool hasReroutingDevice = tObject.getDevice(typeid(MSDevice_Routing)) != nullptr;
517 672946 : if (rerouteDef->closedLanes.size() > 0 && !hasReroutingDevice) {
518 : return true; // an active interval could appear later
519 : }
520 633001 : const MSEdge* lastEdge = tObject.getRerouteDestination();
521 : #ifdef DEBUG_REROUTER
522 : if (DEBUGCOND(tObject)) {
523 : std::cout << SIMTIME << " veh=" << tObject.getID() << " check rerouter " << getID() << " lane=" << Named::getIDSecure(tObject.getLane()) << " edge=" << tObject.getEdge()->getID() << " finalEdge=" << lastEdge->getID() /*<< " arrivalPos=" << tObject.getArrivalPos()*/ << "\n";
524 : }
525 : #endif
526 :
527 633001 : if (rerouteDef->parkProbs.getOverallProb() > 0) {
528 : #ifdef HAVE_FOX
529 104000 : ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
530 : #endif
531 104000 : if (!tObject.isVehicle()) {
532 : return false;
533 : }
534 : SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
535 103935 : bool newDestination = false;
536 : ConstMSEdgeVector newRoute;
537 103935 : MSParkingArea* oldParkingArea = veh.getNextParkingArea();
538 103935 : MSParkingArea* newParkingArea = rerouteParkingArea(rerouteDef, veh, newDestination, newRoute);
539 103935 : if (newParkingArea != nullptr) {
540 : // adapt plans of any riders
541 28829 : for (MSTransportable* p : veh.getPersons()) {
542 40 : p->rerouteParkingArea(oldParkingArea, newParkingArea);
543 : }
544 :
545 28789 : if (newDestination && veh.getParameter().arrivalPosProcedure != ArrivalPosDefinition::DEFAULT) {
546 : // update arrival parameters
547 50 : SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
548 50 : *newParameter = veh.getParameter();
549 50 : newParameter->arrivalPosProcedure = ArrivalPosDefinition::GIVEN;
550 50 : newParameter->arrivalPos = newParkingArea->getEndLanePosition();
551 50 : veh.replaceParameter(newParameter);
552 : }
553 :
554 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
555 12724 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->getClosed())
556 57578 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->getClosed());
557 28789 : const double routeCost = router.recomputeCosts(newRoute, &veh, MSNet::getInstance()->getCurrentTimeStep());
558 28789 : ConstMSEdgeVector prevEdges(veh.getCurrentRouteEdge(), veh.getRoute().end());
559 28789 : const double previousCost = router.recomputeCosts(prevEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
560 28789 : const double savings = previousCost - routeCost;
561 28789 : resetClosedEdges(hasReroutingDevice, veh);
562 : //if (getID() == "ego") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
563 : // << " prevEdges=" << toString(prevEdges)
564 : // << " newEdges=" << toString(edges)
565 : // << "\n";
566 :
567 : std::string errorMsg;
568 28789 : if (veh.replaceParkingArea(newParkingArea, errorMsg)) {
569 57578 : veh.replaceRouteEdges(newRoute, routeCost, savings, getID() + ":" + toString(SUMO_TAG_PARKING_AREA_REROUTE), false, false, false);
570 28789 : if (oldParkingArea->isReservable()) {
571 20 : oldParkingArea->removeSpaceReservation(&veh);
572 : }
573 28789 : if (newParkingArea->isReservable()) {
574 20 : newParkingArea->addSpaceReservation(&veh);
575 : }
576 : } else {
577 0 : WRITE_WARNING("Vehicle '" + veh.getID() + "' at rerouter '" + getID()
578 : + "' could not reroute to new parkingArea '" + newParkingArea->getID()
579 : + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
580 : }
581 28789 : } else {
582 75146 : if (oldParkingArea && oldParkingArea->isReservable()) {
583 10 : oldParkingArea->addSpaceReservation(&veh);
584 : }
585 : }
586 : return false;
587 103935 : }
588 529001 : if (rerouteDef->overtakeLocations.size() > 0) {
589 144 : if (!tObject.isVehicle()) {
590 : return false;
591 : }
592 : SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
593 144 : const ConstMSEdgeVector& oldEdges = veh.getRoute().getEdges();
594 : double bestSavings = -std::numeric_limits<double>::max();
595 : double netSaving;
596 : int bestIndex = -1;
597 : MSRouteIterator bestMainStart = oldEdges.end();
598 : std::pair<const SUMOVehicle*, MSRailSignal*> best_overtaker_signal(nullptr, nullptr);
599 : int index = -1;
600 : // sort locations by descending distance to vehicle
601 : std::vector<std::pair<int, int> > sortedLocs;
602 330 : for (const OvertakeLocation& oloc : rerouteDef->overtakeLocations) {
603 186 : index++;
604 186 : if (veh.getLength() > oloc.sidingLength) {
605 3 : continue;
606 : }
607 183 : auto mainStart = std::find(veh.getCurrentRouteEdge(), oldEdges.end(), oloc.main.front());
608 183 : if (mainStart == oldEdges.end()
609 : // exit main within
610 366 : || ConstMSEdgeVector(mainStart, mainStart + oloc.main.size()) != oloc.cMain
611 : // stop in main
612 366 : || (veh.hasStops() && veh.getNextStop().edge < (mainStart + oloc.main.size()))) {
613 : //std::cout << SIMTIME << " veh=" << veh.getID() << " wrong route or stop\n";
614 0 : continue;
615 : }
616 : // negated iterator distance for descending order
617 183 : sortedLocs.push_back(std::make_pair(-(int)(mainStart - veh.getCurrentRouteEdge()), index));
618 : }
619 144 : std::sort(sortedLocs.begin(), sortedLocs.end());
620 327 : for (const auto& item : sortedLocs) {
621 183 : index = item.second;
622 183 : const OvertakeLocation& oloc = rerouteDef->overtakeLocations[index];
623 183 : auto mainStart = veh.getCurrentRouteEdge() - item.first; // subtracting negative difference
624 183 : std::pair<const SUMOVehicle*, MSRailSignal*> overtaker_signal = overtakingTrain(veh, mainStart, oloc, netSaving);
625 183 : if (overtaker_signal.first != nullptr && netSaving > bestSavings) {
626 : bestSavings = netSaving;
627 : bestIndex = index;
628 : best_overtaker_signal = overtaker_signal;
629 : bestMainStart = mainStart;
630 : #ifdef DEBUG_OVERTAKING
631 : std::cout << " newBest index=" << bestIndex << " saving=" << bestSavings << "\n";
632 : #endif
633 : }
634 : }
635 144 : if (bestIndex >= 0) {
636 41 : const OvertakeLocation& oloc = rerouteDef->overtakeLocations[bestIndex];
637 41 : if (oloc.defer) {
638 5 : return false;
639 : }
640 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
641 0 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->getClosed())
642 72 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->getClosed());
643 36 : ConstMSEdgeVector newEdges(veh.getCurrentRouteEdge(), bestMainStart);
644 36 : newEdges.insert(newEdges.end(), oloc.siding.begin(), oloc.siding.end());
645 36 : newEdges.insert(newEdges.end(), bestMainStart + oloc.main.size(), oldEdges.end());
646 36 : const double routeCost = router.recomputeCosts(newEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
647 36 : const double savings = (router.recomputeCosts(oloc.cMain, &veh, MSNet::getInstance()->getCurrentTimeStep())
648 36 : - router.recomputeCosts(oloc.cSiding, &veh, MSNet::getInstance()->getCurrentTimeStep()));
649 72 : const std::string info = getID() + ":" + toString(SUMO_TAG_OVERTAKING_REROUTE) + ":" + best_overtaker_signal.first->getID();
650 36 : veh.replaceRouteEdges(newEdges, routeCost, savings, info, false, false, false);
651 36 : oloc.sidingExit->addConstraint(veh.getID(), new MSRailSignalConstraint_Predecessor(
652 36 : MSRailSignalConstraint::PREDECESSOR, best_overtaker_signal.second, best_overtaker_signal.first->getID(), 100, true));
653 36 : resetClosedEdges(hasReroutingDevice, veh);
654 36 : }
655 139 : return false;
656 144 : }
657 528857 : if (rerouteDef->stopAlternatives.size() > 0) {
658 : // somewhat similar to parkProbs but taking into account public transport schedule
659 12 : if (!tObject.isVehicle()) {
660 : return false;
661 : }
662 12 : checkStopSwitch(static_cast<MSBaseVehicle&>(tObject), rerouteDef);
663 : }
664 : // get rerouting params
665 528857 : ConstMSRoutePtr newRoute = rerouteDef->routeProbs.getOverallProb() > 0 ? rerouteDef->routeProbs.get() : nullptr;
666 : // we will use the route if given rather than calling our own dijsktra...
667 528857 : if (newRoute != nullptr) {
668 : #ifdef DEBUG_REROUTER
669 : if (DEBUGCOND(tObject)) {
670 : std::cout << " replacedRoute from routeDist " << newRoute->getID() << "\n";
671 : }
672 : #endif
673 522921 : tObject.replaceRoute(newRoute, getID());
674 522918 : return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
675 : }
676 : const MSEdge* newEdge = lastEdge;
677 : // ok, try using a new destination
678 : double newArrivalPos = -1;
679 5939 : const MSEdgeVector closedEdges = rerouteDef->getClosedEdges();
680 5939 : const bool destUnreachable = std::find(closedEdges.begin(), closedEdges.end(), lastEdge) != closedEdges.end();
681 : bool keepDestination = false;
682 : // if we have a closingReroute, only assign new destinations to vehicles which cannot reach their original destination
683 : // if we have a closingLaneReroute, no new destinations should be assigned
684 5939 : if (closedEdges.empty() || destUnreachable || rerouteDef->isVia) {
685 4177 : newEdge = rerouteDef->edgeProbs.getOverallProb() > 0 ? rerouteDef->edgeProbs.get() : lastEdge;
686 : assert(newEdge != nullptr);
687 4177 : if (newEdge == &mySpecialDest_terminateRoute) {
688 : keepDestination = true;
689 55 : newEdge = tObject.getEdge();
690 55 : newArrivalPos = tObject.getPositionOnLane(); // instant arrival
691 4122 : } else if (newEdge == &mySpecialDest_keepDestination || newEdge == lastEdge) {
692 1578 : if (destUnreachable && rerouteDef->permissionsAllowAll) {
693 : // if permissions aren't set vehicles will simply drive through
694 : // the closing unless terminated. If the permissions are specified, assume that the user wants
695 : // vehicles to stand and wait until the closing ends
696 63 : WRITE_WARNINGF(TL("Cannot keep destination edge '%' for vehicle '%' due to closed edges. Terminating route."), lastEdge->getID(), tObject.getID());
697 21 : newEdge = tObject.getEdge();
698 : } else {
699 : newEdge = lastEdge;
700 : }
701 : }
702 : }
703 : ConstMSEdgeVector edges;
704 : std::vector<MSTransportableRouter::TripItem> items;
705 : // we have a new destination, let's replace the route (if it is affected)
706 5939 : MSEdgeVector closed = rerouteDef->getClosedEdges();
707 5939 : Prohibitions prohibited = rerouteDef->getClosed();
708 7701 : if (rerouteDef->closed.empty() || destUnreachable || rerouteDef->isVia || affected(tObject.getUpcomingEdgeIDs(), closed)) {
709 5862 : if (tObject.isVehicle()) {
710 : SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
711 4392 : const bool canChangeDest = rerouteDef->edgeProbs.getOverallProb() > 0;
712 : MSVehicleRouter& router = hasReroutingDevice
713 4392 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), prohibited)
714 1724 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), prohibited);
715 4392 : bool ok = veh.reroute(now, getID(), router, false, false, canChangeDest, newEdge);
716 4389 : if (!ok && !keepDestination && canChangeDest) {
717 : // destination unreachable due to closed intermediate edges. pick among alternative targets
718 82 : RandomDistributor<MSEdge*> edgeProbs2 = rerouteDef->edgeProbs;
719 82 : edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
720 152 : while (!ok && edgeProbs2.getVals().size() > 0) {
721 110 : newEdge = edgeProbs2.get();
722 110 : edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
723 110 : if (newEdge == &mySpecialDest_terminateRoute) {
724 42 : newEdge = veh.getEdge();
725 42 : newArrivalPos = veh.getPositionOnLane(); // instant arrival
726 : }
727 110 : if (newEdge == &mySpecialDest_keepDestination && !rerouteDef->permissionsAllowAll) {
728 : newEdge = lastEdge;
729 : break;
730 : }
731 70 : ok = veh.reroute(now, getID(), router, false, false, true, newEdge);
732 : }
733 :
734 : }
735 4389 : if (!rerouteDef->isVia) {
736 : #ifdef DEBUG_REROUTER
737 : if (DEBUGCOND(tObject)) std::cout << " rerouting: newDest=" << newEdge->getID()
738 : << " newEdges=" << toString(edges)
739 : << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
740 : << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->getClosedEdges()) << "\n";
741 : #endif
742 4389 : if (ok && newArrivalPos != -1) {
743 : // must be called here because replaceRouteEdges may also set the arrivalPos
744 86 : veh.setArrivalPos(newArrivalPos);
745 : }
746 :
747 : }
748 : } else {
749 : // person rerouting here
750 : MSTransportableRouter& router = hasReroutingDevice
751 1470 : ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), prohibited)
752 1470 : : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, prohibited);
753 4410 : const bool success = router.compute(tObject.getEdge(), newEdge, tObject.getPositionOnLane(), "",
754 1470 : rerouteDef->isVia ? newEdge->getLength() / 2. : tObject.getParameter().arrivalPos, "",
755 1470 : tObject.getMaxSpeed(), nullptr, tObject.getVTypeParameter(), 0, now, items);
756 1470 : if (!rerouteDef->isVia) {
757 700 : if (success) {
758 1400 : for (const MSTransportableRouter::TripItem& it : items) {
759 700 : if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
760 : edges.pop_back();
761 : }
762 700 : edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
763 700 : if (!edges.empty()) {
764 700 : static_cast<MSPerson&>(tObject).replaceWalk(edges, tObject.getPositionOnLane(), 0, 1);
765 : }
766 : }
767 : } else {
768 : // maybe the pedestrian model still finds a way (JuPedSim)
769 0 : static_cast<MSPerson&>(tObject).replaceWalk({tObject.getEdge(), newEdge}, tObject.getPositionOnLane(), 0, 1);
770 : }
771 : }
772 : }
773 5859 : if (!prohibited.empty()) {
774 1767 : resetClosedEdges(hasReroutingDevice, tObject);
775 : }
776 : }
777 : // it was only a via so calculate the remaining part
778 5936 : if (rerouteDef->isVia) {
779 770 : if (tObject.isVehicle()) {
780 : SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
781 0 : if (!edges.empty()) {
782 : edges.pop_back();
783 : }
784 : MSVehicleRouter& router = hasReroutingDevice
785 0 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), prohibited)
786 0 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), prohibited);
787 0 : router.compute(newEdge, lastEdge, &veh, now, edges);
788 0 : const double routeCost = router.recomputeCosts(edges, &veh, now);
789 : hasReroutingDevice
790 0 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass())
791 0 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
792 0 : const bool useNewRoute = veh.replaceRouteEdges(edges, routeCost, 0, getID());
793 : #ifdef DEBUG_REROUTER
794 : if (DEBUGCOND(tObject)) std::cout << " rerouting: newDest=" << newEdge->getID()
795 : << " newEdges=" << toString(edges)
796 : << " useNewRoute=" << useNewRoute << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
797 : << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->getClosedEdges()) << "\n";
798 : #endif
799 0 : if (useNewRoute && newArrivalPos != -1) {
800 : // must be called here because replaceRouteEdges may also set the arrivalPos
801 0 : veh.setArrivalPos(newArrivalPos);
802 : }
803 : } else {
804 : // person rerouting here
805 770 : bool success = !items.empty();
806 770 : if (success) {
807 : MSTransportableRouter& router = hasReroutingDevice
808 770 : ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), prohibited)
809 770 : : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, prohibited);
810 2310 : success = router.compute(newEdge, lastEdge, newEdge->getLength() / 2., "",
811 770 : tObject.getParameter().arrivalPos, "",
812 770 : tObject.getMaxSpeed(), nullptr, tObject.getVTypeParameter(), 0, now, items);
813 : }
814 770 : if (success) {
815 2310 : for (const MSTransportableRouter::TripItem& it : items) {
816 1540 : if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
817 : edges.pop_back();
818 : }
819 1540 : edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
820 : }
821 770 : if (!edges.empty()) {
822 770 : static_cast<MSPerson&>(tObject).replaceWalk(edges, tObject.getPositionOnLane(), 0, 1);
823 : }
824 : } else {
825 : // maybe the pedestrian model still finds a way (JuPedSim)
826 3 : static_cast<MSPerson&>(tObject).replaceWalk({tObject.getEdge(), newEdge, lastEdge}, tObject.getPositionOnLane(), 0, 1);
827 : }
828 : }
829 770 : if (!prohibited.empty()) {
830 0 : resetClosedEdges(hasReroutingDevice, tObject);
831 : }
832 : }
833 : return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
834 5948 : }
835 :
836 :
837 : void
838 1 : MSTriggeredRerouter::setUserMode(bool val) {
839 1 : myAmInUserMode = val;
840 1 : }
841 :
842 :
843 : void
844 1 : MSTriggeredRerouter::setUserUsageProbability(double prob) {
845 1 : myUserProbability = prob;
846 1 : }
847 :
848 :
849 : bool
850 0 : MSTriggeredRerouter::inUserMode() const {
851 0 : return myAmInUserMode;
852 : }
853 :
854 :
855 : double
856 5964 : MSTriggeredRerouter::getProbability() const {
857 5964 : return myAmInUserMode ? myUserProbability : myProbability;
858 : }
859 :
860 :
861 : double
862 0 : MSTriggeredRerouter::getUserProbability() const {
863 0 : return myUserProbability;
864 : }
865 :
866 :
867 : double
868 96484 : MSTriggeredRerouter::getStoppingPlaceOccupancy(MSStoppingPlace* sp, const SUMOVehicle* veh) {
869 96484 : return (double)(sp->getElement() == SUMO_TAG_PARKING_AREA
870 96448 : ? dynamic_cast<MSParkingArea*>(sp)->getOccupancyIncludingRemoteReservations(veh)
871 36 : : sp->getStoppedVehicles().size());
872 : }
873 :
874 :
875 : double
876 93757 : MSTriggeredRerouter::getLastStepStoppingPlaceOccupancy(MSStoppingPlace* sp, const SUMOVehicle* veh) {
877 93757 : return (double)(sp->getElement() == SUMO_TAG_PARKING_AREA
878 93721 : ? dynamic_cast<MSParkingArea*>(sp)->getLastStepOccupancyIncludingRemoteReservations(veh)
879 36 : : sp->getStoppedVehicles().size());
880 : }
881 :
882 :
883 : double
884 275916 : MSTriggeredRerouter::getStoppingPlaceCapacity(MSStoppingPlace* sp) {
885 : if (myBlockedStoppingPlaces.count(sp) == 0) {
886 : return (double)(sp->getElement() == SUMO_TAG_PARKING_AREA
887 275900 : ? dynamic_cast<MSParkingArea*>(sp)->getCapacity()
888 : // assume only one vehicle at a time (for stationReroute)
889 : : 1.);
890 : } else {
891 : return 0.;
892 : }
893 : }
894 :
895 :
896 : void
897 89206 : MSTriggeredRerouter::rememberBlockedStoppingPlace(SUMOVehicle& veh, const MSStoppingPlace* parkingArea, bool blocked) {
898 89206 : veh.rememberBlockedParkingArea(parkingArea, blocked);
899 89206 : }
900 :
901 :
902 : void
903 131724 : MSTriggeredRerouter::rememberStoppingPlaceScore(SUMOVehicle& veh, MSStoppingPlace* parkingArea, const std::string& score) {
904 131724 : veh.rememberParkingAreaScore(parkingArea, score);
905 131724 : }
906 :
907 :
908 : void
909 29564 : MSTriggeredRerouter::resetStoppingPlaceScores(SUMOVehicle& veh) {
910 29564 : veh.resetParkingAreaScores();
911 29564 : }
912 :
913 :
914 : SUMOTime
915 71557 : MSTriggeredRerouter::sawBlockedStoppingPlace(SUMOVehicle& veh, MSStoppingPlace* parkingArea, bool local) {
916 71557 : return veh.sawBlockedParkingArea(parkingArea, local);
917 : }
918 :
919 :
920 : int
921 68516 : MSTriggeredRerouter::getNumberStoppingPlaceReroutes(SUMOVehicle& veh) {
922 68516 : return veh.getNumberParkingReroutes();
923 : }
924 :
925 :
926 : void
927 29564 : MSTriggeredRerouter::setNumberStoppingPlaceReroutes(SUMOVehicle& veh, int value) {
928 29564 : veh.setNumberParkingReroutes(value);
929 29564 : }
930 :
931 :
932 : MSParkingArea*
933 103935 : MSTriggeredRerouter::rerouteParkingArea(const MSTriggeredRerouter::RerouteInterval* rerouteDef,
934 : SUMOVehicle& veh, bool& newDestination, ConstMSEdgeVector& newRoute) {
935 103935 : MSStoppingPlace* destStoppingPlace = veh.getNextParkingArea();
936 103935 : if (destStoppingPlace == nullptr) {
937 : // not driving towards the right type of stop
938 : return nullptr;
939 : }
940 : std::vector<StoppingPlaceVisible> parks;
941 295075 : for (auto cand : rerouteDef->parkProbs.getVals()) {
942 201230 : if (cand.first->accepts(&veh)) {
943 200550 : parks.push_back(cand);
944 : }
945 : }
946 : StoppingPlaceParamMap_t addInput = {};
947 187690 : return dynamic_cast<MSParkingArea*>(rerouteStoppingPlace(destStoppingPlace, parks, rerouteDef->parkProbs.getProbs(), veh, newDestination, newRoute, addInput, rerouteDef->getClosed()));
948 93845 : }
949 :
950 :
951 : std::pair<const SUMOVehicle*, MSRailSignal*>
952 183 : MSTriggeredRerouter::overtakingTrain(const SUMOVehicle& veh,
953 : ConstMSEdgeVector::const_iterator mainStart,
954 : const OvertakeLocation& oloc,
955 : double& netSaving) {
956 183 : const ConstMSEdgeVector& route = veh.getRoute().getEdges();
957 : const MSEdgeVector& main = oloc.main;
958 183 : const double vMax = veh.getMaxSpeed();
959 366 : const double prio = veh.getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".prio", false, DEFAULT_PRIO_OVERTAKEN, false);
960 183 : MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
961 437 : for (MSVehicleControl::constVehIt it_veh = c.loadedVehBegin(); it_veh != c.loadedVehEnd(); ++it_veh) {
962 307 : const MSBaseVehicle* veh2 = dynamic_cast<const MSBaseVehicle*>((*it_veh).second);
963 307 : if (veh2->isOnRoad() && veh2->getMaxSpeed() > vMax) {
964 93 : const double arrivalDelay = veh2->getStopArrivalDelay();
965 182 : const double delay = MAX2(veh2->getStopDelay(), arrivalDelay == INVALID_DOUBLE ? 0 : arrivalDelay);
966 279 : if (delay > veh2->getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".maxDelay", false, DEFAULT_MAXDELAY, false)) {
967 : continue;
968 : }
969 89 : const ConstMSEdgeVector& route2 = veh2->getRoute().getEdges();
970 : auto itOnMain2 = route2.end();
971 : int mainIndex = 0;
972 110 : for (const MSEdge* m : main) {
973 105 : itOnMain2 = std::find(veh2->getCurrentRouteEdge(), route2.end(), m);
974 105 : if (itOnMain2 != route2.end()) {
975 : break;
976 : }
977 21 : mainIndex++;
978 : }
979 89 : if (itOnMain2 != route2.end() && itOnMain2 > veh2->getCurrentRouteEdge()) {
980 : auto itOnMain = mainStart + mainIndex;
981 : double timeToMain = 0;
982 371 : for (auto it = veh.getCurrentRouteEdge(); it != itOnMain; it++) {
983 290 : timeToMain += (*it)->getMinimumTravelTime(&veh);
984 : }
985 : // veh2 may be anywhere on the current edge so we have to discount
986 81 : double timeToMain2 = -veh2->getEdge()->getMinimumTravelTime(veh2) * veh2->getPositionOnLane() / veh2->getEdge()->getLength();
987 : double timeToLastSignal2 = timeToMain2;
988 562 : for (auto it = veh2->getCurrentRouteEdge(); it != itOnMain2; it++) {
989 481 : timeToMain2 += (*it)->getMinimumTravelTime(veh2);
990 481 : auto signal = getRailSignal(*it);
991 481 : if (signal) {
992 : timeToLastSignal2 = timeToMain2;
993 : #ifdef DEBUG_OVERTAKING
994 : std::cout << " lastBeforeMain2 " << signal->getID() << "\n";
995 : #endif
996 : }
997 : }
998 : double exitMainTime = timeToMain;
999 : double exitMainBlockTime2 = timeToMain2;
1000 : double commonTime = 0;
1001 : double commonTime2 = 0;
1002 : int nCommon = 0;
1003 : auto exitMain2 = itOnMain2;
1004 : const MSRailSignal* firstAfterMain = nullptr;
1005 : const MSEdge* common = nullptr;
1006 81 : double vMinCommon = (*itOnMain)->getVehicleMaxSpeed(&veh);
1007 81 : double vMinCommon2 = (*itOnMain2)->getVehicleMaxSpeed(veh2);
1008 : while (itOnMain2 != route2.end()
1009 794 : && itOnMain != route.end()
1010 1657 : && *itOnMain == *itOnMain2) {
1011 : common = *itOnMain;
1012 785 : commonTime += common->getMinimumTravelTime(&veh);
1013 785 : commonTime2 += common->getMinimumTravelTime(veh2);
1014 785 : vMinCommon = MIN2(vMinCommon, common->getVehicleMaxSpeed(&veh));
1015 785 : vMinCommon2 = MIN2(vMinCommon2, common->getVehicleMaxSpeed(veh2));
1016 785 : const bool onMain = nCommon < (int)main.size() - mainIndex;
1017 785 : if (onMain) {
1018 240 : exitMainTime = timeToMain + commonTime;
1019 : }
1020 785 : if (firstAfterMain == nullptr) {
1021 480 : exitMainBlockTime2 = timeToMain2 + commonTime2;
1022 : }
1023 785 : auto signal = getRailSignal(common);
1024 785 : if (signal) {
1025 318 : if (!onMain && firstAfterMain == nullptr) {
1026 : firstAfterMain = signal;
1027 : #ifdef DEBUG_OVERTAKING
1028 : std::cout << " firstAfterMain " << signal->getID() << "\n";
1029 : #endif
1030 : }
1031 : }
1032 785 : nCommon++;
1033 : itOnMain++;
1034 : itOnMain2++;
1035 : }
1036 81 : const double vMaxLast = common->getVehicleMaxSpeed(&veh);
1037 81 : const double vMaxLast2 = common->getVehicleMaxSpeed(veh2);
1038 81 : commonTime += veh.getLength() / vMaxLast;
1039 81 : exitMainBlockTime2 += veh2->getLength() / vMaxLast2;
1040 81 : exitMain2 += MIN2(nCommon, (int)main.size() - mainIndex);
1041 81 : double timeLoss2 = MAX2(0.0, timeToMain + veh.getLength() / oloc.siding.front()->getVehicleMaxSpeed(&veh) - timeToLastSignal2);
1042 81 : const double saving = timeToMain + commonTime - (timeToMain2 + commonTime2) - timeLoss2;
1043 81 : const double loss = exitMainBlockTime2 - exitMainTime;
1044 162 : const double prio2 = veh2->getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".prio", false, DEFAULT_PRIO_OVERTAKER, false);
1045 : // losses from acceleration after stopping at a signal
1046 81 : const double accelTimeLoss = loss > 0 ? 0.5 * vMinCommon / veh.getVehicleType().getCarFollowModel().getMaxAccel() : 0;
1047 81 : const double accelTimeLoss2 = timeLoss2 > 0 ? 0.5 * vMinCommon2 / veh2->getVehicleType().getCarFollowModel().getMaxAccel() : 0;
1048 81 : netSaving = prio2 * (saving - accelTimeLoss2) - prio * (loss + accelTimeLoss);
1049 : #ifdef DEBUG_OVERTAKING
1050 : std::cout << SIMTIME << " veh=" << veh.getID() << " veh2=" << veh2->getID()
1051 : << " sidingStart=" << oloc.siding.front()->getID()
1052 : << " ttm=" << timeToMain << " ttm2=" << timeToMain2
1053 : << " nCommon=" << nCommon << " cT=" << commonTime << " cT2=" << commonTime2
1054 : << " em=" << exitMainTime << " emb2=" << exitMainBlockTime2
1055 : << " ttls2=" << timeToLastSignal2
1056 : << " saving=" << saving << " loss=" << loss
1057 : << " atl=" << accelTimeLoss << " atl2=" << accelTimeLoss2 << " tl2=" << timeLoss2
1058 : << " prio=" << prio << " prio2=" << prio2 << " netSaving=" << netSaving << "\n";
1059 : #endif
1060 81 : if (netSaving > oloc.minSaving) {
1061 53 : MSRailSignal* s = findSignal(veh2->getCurrentRouteEdge(), exitMain2);
1062 53 : if (s != nullptr) {
1063 53 : return std::make_pair(veh2, s);
1064 : }
1065 : }
1066 : }
1067 : }
1068 : }
1069 130 : return std::make_pair(nullptr, nullptr);
1070 : }
1071 :
1072 :
1073 : void
1074 12 : MSTriggeredRerouter::checkStopSwitch(MSBaseVehicle& ego, const MSTriggeredRerouter::RerouteInterval* def) {
1075 : myBlockedStoppingPlaces.clear();
1076 : #ifdef DEBUG_REROUTER
1077 : std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << "\n";
1078 : #endif
1079 12 : if (!ego.hasStops()) {
1080 0 : return;
1081 : }
1082 12 : const MSStop& stop = ego.getNextStop();
1083 12 : if (stop.reached || stop.joinTriggered || (stop.pars.arrival < 0 && stop.pars.until < 0)) {
1084 : return;
1085 : }
1086 12 : MSStoppingPlace* cur = nullptr;
1087 24 : for (MSStoppingPlace* sp : stop.getPlaces()) {
1088 12 : for (auto item : def->stopAlternatives) {
1089 12 : if (sp == item.first) {
1090 12 : cur = sp;
1091 12 : break;
1092 : }
1093 : }
1094 12 : }
1095 12 : if (cur == nullptr) {
1096 : return;
1097 : }
1098 12 : std::vector<const SUMOVehicle*> stopped = cur->getStoppedVehicles();
1099 : #ifdef DEBUG_REROUTER
1100 : std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopped=" << toString(stopped) << "\n";
1101 : #endif
1102 : SUMOTime stoppedDuration = -1;
1103 12 : if (stopped.empty()) {
1104 : /// look upstream for vehicles that stop on this lane before ego arrives
1105 8 : const MSLane& stopLane = cur->getLane();
1106 8 : MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
1107 25 : for (MSVehicleControl::constVehIt it_veh = c.loadedVehBegin(); it_veh != c.loadedVehEnd(); ++it_veh) {
1108 17 : const MSBaseVehicle* veh = dynamic_cast<const MSBaseVehicle*>((*it_veh).second);
1109 17 : if (veh->isOnRoad() && veh->hasStops()) {
1110 17 : const MSStop& vehStop = veh->getNextStop();
1111 17 : if (vehStop.pars.lane == stopLane.getID()) {
1112 : myBlockedStoppingPlaces.insert(cur);
1113 10 : if (veh->isStopped()) {
1114 : // stopped somewhere else on the same lane
1115 2 : stoppedDuration = MAX3((SUMOTime)0, stoppedDuration, veh->getStopDuration());
1116 : } else {
1117 8 : std::pair<double, double> timeDist = veh->estimateTimeToNextStop();
1118 8 : SUMOTime timeTo = TIME2STEPS(timeDist.first);
1119 8 : stoppedDuration = MAX3((SUMOTime)0, stoppedDuration, timeTo + vehStop.getMinDuration(SIMSTEP + timeTo));
1120 : }
1121 : }
1122 : }
1123 : }
1124 : } else {
1125 : stoppedDuration = 0;
1126 8 : for (const SUMOVehicle* veh : cur->getStoppedVehicles()) {
1127 4 : stoppedDuration = MAX2(stoppedDuration, veh->getStopDuration());
1128 4 : }
1129 : }
1130 12 : if (stoppedDuration < 0) {
1131 : return;
1132 : }
1133 : /// @todo: consider time for conflict veh to leave the block
1134 12 : const SUMOTime stopFree = SIMSTEP + stoppedDuration;
1135 12 : const SUMOTime scheduledArrival = stop.pars.arrival >= 0 ? stop.pars.arrival : stop.pars.until - stop.pars.duration;
1136 : #ifdef DEBUG_REROUTER
1137 : std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopFree=" << stopFree << " scheduledArrival=" << time2string(scheduledArrival) << "\n";
1138 : #endif
1139 12 : if (stopFree < scheduledArrival) {
1140 : // no conflict according to the schedule
1141 : return;
1142 : }
1143 12 : const SUMOTime estimatedArrival = SIMSTEP + (stop.pars.arrival >= 0
1144 12 : ? TIME2STEPS(ego.getStopArrivalDelay())
1145 16 : : TIME2STEPS(ego.getStopDelay()) - stop.pars.duration);
1146 : #ifdef DEBUG_REROUTER
1147 : std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopFree=" << stopFree << " estimatedArrival=" << time2string(estimatedArrival) << "\n";
1148 : #endif
1149 12 : if (stopFree < estimatedArrival) {
1150 : // no conflict when considering current delay
1151 : return;
1152 : }
1153 12 : const std::vector<double> probs(def->stopAlternatives.size(), 1.);
1154 : StoppingPlaceParamMap_t scores = {};
1155 : bool newDestination;
1156 : ConstMSEdgeVector newRoute;
1157 : // @todo: consider future conflicts caused by rerouting
1158 : // @todo: reject alternatives with large detour
1159 12 : const MSStoppingPlace* alternative = rerouteStoppingPlace(nullptr, def->stopAlternatives, probs, ego, newDestination, newRoute, scores);
1160 : #ifdef DEBUG_REROUTER
1161 : std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " alternative=" << Named::getIDSecure(alternative) << "\n";
1162 : #endif
1163 12 : if (alternative != nullptr) {
1164 : // @todo adapt plans of any riders
1165 : //for (MSTransportable* p : ego.getPersons()) {
1166 : // p->rerouteParkingArea(ego.getNextParkingArea(), newParkingArea);
1167 : //}
1168 :
1169 12 : if (newDestination && ego.getParameter().arrivalPosProcedure != ArrivalPosDefinition::DEFAULT) {
1170 : // update arrival parameters
1171 0 : SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
1172 0 : *newParameter = ego.getParameter();
1173 0 : newParameter->arrivalPosProcedure = ArrivalPosDefinition::GIVEN;
1174 0 : newParameter->arrivalPos = alternative->getEndLanePosition();
1175 0 : ego.replaceParameter(newParameter);
1176 : }
1177 :
1178 12 : SUMOVehicleParameter::Stop newStop = stop.pars;
1179 12 : newStop.lane = alternative->getLane().getID();
1180 12 : newStop.startPos = alternative->getBeginLanePosition();
1181 12 : newStop.endPos = alternative->getEndLanePosition();
1182 12 : switch (alternative->getElement()) {
1183 0 : case SUMO_TAG_PARKING_AREA:
1184 : newStop.parkingarea = alternative->getID();
1185 : break;
1186 0 : case SUMO_TAG_CONTAINER_STOP:
1187 : newStop.containerstop = alternative->getID();
1188 : break;
1189 0 : case SUMO_TAG_CHARGING_STATION:
1190 : newStop.chargingStation = alternative->getID();
1191 : break;
1192 0 : case SUMO_TAG_OVERHEAD_WIRE_SEGMENT:
1193 : newStop.overheadWireSegment = alternative->getID();
1194 : break;
1195 12 : case SUMO_TAG_BUS_STOP:
1196 : case SUMO_TAG_TRAIN_STOP:
1197 : default:
1198 : newStop.busstop = alternative->getID();
1199 : }
1200 : std::string errorMsg;
1201 24 : if (!ego.replaceStop(0, newStop, getID() + ":" + toString(SUMO_TAG_STATION_REROUTE), false, errorMsg)) {
1202 0 : WRITE_WARNING("Vehicle '" + ego.getID() + "' at rerouter '" + getID()
1203 : + "' could not perform stationReroute to '" + alternative->getID()
1204 : + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
1205 : }
1206 12 : }
1207 24 : }
1208 :
1209 :
1210 : MSRailSignal*
1211 152 : MSTriggeredRerouter::findSignal(ConstMSEdgeVector::const_iterator begin, ConstMSEdgeVector::const_iterator end) {
1212 152 : auto it = end;
1213 : do {
1214 : it--;
1215 304 : auto signal = getRailSignal(*it);
1216 304 : if (signal != nullptr) {
1217 152 : return signal;
1218 : }
1219 152 : } while (it != begin);
1220 : return nullptr;
1221 : }
1222 :
1223 :
1224 : MSRailSignal*
1225 1570 : MSTriggeredRerouter::getRailSignal(const MSEdge* edge) {
1226 1570 : if (edge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
1227 732 : for (const MSLink* link : edge->getLanes().front()->getLinkCont()) {
1228 732 : if (link->getTLLogic() != nullptr) {
1229 732 : return dynamic_cast<MSRailSignal*>(const_cast<MSTrafficLightLogic*>(link->getTLLogic()));
1230 : }
1231 : }
1232 : }
1233 : return nullptr;
1234 : }
1235 :
1236 : bool
1237 1193712 : MSTriggeredRerouter::applies(const SUMOTrafficObject& obj) const {
1238 1193712 : if (myVehicleTypes.empty() || myVehicleTypes.count(obj.getVehicleType().getOriginalID()) > 0) {
1239 1193642 : return true;
1240 : } else {
1241 140 : std::set<std::string> vTypeDists = MSNet::getInstance()->getVehicleControl().getVTypeDistributionMembership(obj.getVehicleType().getOriginalID());
1242 70 : for (auto vTypeDist : vTypeDists) {
1243 : if (myVehicleTypes.count(vTypeDist) > 0) {
1244 : return true;
1245 : }
1246 : }
1247 70 : return false;
1248 : }
1249 : }
1250 :
1251 :
1252 : bool
1253 130876 : MSTriggeredRerouter::affected(const std::set<SUMOTrafficObject::NumericalID>& edgeIndices, const MSEdgeVector& closed) {
1254 149177 : for (const MSEdge* const e : closed) {
1255 69807 : if (edgeIndices.count(e->getNumericalID()) > 0) {
1256 : return true;
1257 : }
1258 : }
1259 : return false;
1260 : }
1261 :
1262 :
1263 : void
1264 25459 : MSTriggeredRerouter::checkParkingRerouteConsistency() {
1265 : // if a parkingArea is a rerouting target, it should generally have a
1266 : // rerouter on its edge or vehicles will be stuck there once it's full.
1267 : // The user should receive a Warning in this case
1268 : std::set<MSEdge*> parkingRerouterEdges;
1269 : std::map<MSParkingArea*, std::string, ComparatorIdLess> targetedParkingArea; // paID -> targetingRerouter
1270 29450 : for (const auto& rr : myInstances) {
1271 : bool hasParkingReroute = false;
1272 7839 : for (const RerouteInterval& interval : rr.second->myIntervals) {
1273 3848 : if (interval.parkProbs.getOverallProb() > 0) {
1274 : hasParkingReroute = true;
1275 15834 : for (const StoppingPlaceVisible& pav : interval.parkProbs.getVals()) {
1276 27162 : targetedParkingArea[dynamic_cast<MSParkingArea*>(pav.first)] = rr.first;
1277 : }
1278 : }
1279 : }
1280 3991 : if (hasParkingReroute) {
1281 2253 : parkingRerouterEdges.insert(rr.second->myEdges.begin(), rr.second->myEdges.end());
1282 : }
1283 : }
1284 28354 : for (const auto& item : targetedParkingArea) {
1285 2895 : if (parkingRerouterEdges.count(&item.first->getLane().getEdge()) == 0) {
1286 1312 : WRITE_WARNINGF(TL("ParkingArea '%' is targeted by rerouter '%' but doesn't have its own rerouter. This may cause parking search to abort."),
1287 : item.first->getID(), item.second);
1288 : }
1289 : }
1290 25459 : }
1291 :
1292 :
1293 : void
1294 30592 : MSTriggeredRerouter::resetClosedEdges(bool hasReroutingDevice, const SUMOTrafficObject& o) {
1295 : // getRouterTT without prohibitions removes previous prohibitions
1296 30592 : if (o.isVehicle()) {
1297 : hasReroutingDevice
1298 61184 : ? MSRoutingEngine::getRouterTT(o.getRNGIndex(), o.getVClass())
1299 48171 : : MSNet::getInstance()->getRouterTT(o.getRNGIndex());
1300 : } else {
1301 : hasReroutingDevice
1302 0 : ? MSRoutingEngine::getIntermodalRouterTT(o.getRNGIndex())
1303 0 : : MSNet::getInstance()->getIntermodalRouter(o.getRNGIndex(), 0);
1304 : }
1305 30592 : }
1306 :
1307 : /****************************************************************************/
|