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 4077 : MSTriggeredRerouter::MSTriggeredRerouter(const std::string& id,
88 : const MSEdgeVector& edges, double prob, bool off, bool optional,
89 4077 : SUMOTime timeThreshold, const std::string& vTypes, const Position& pos, const double radius) :
90 : Named(id),
91 : MSMoveReminder(id),
92 : MSStoppingPlaceRerouter("parking"),
93 4077 : myEdges(edges),
94 4077 : myProbability(prob),
95 4077 : myUserProbability(prob),
96 4077 : myAmInUserMode(false),
97 4077 : myAmOptional(optional),
98 4077 : myPosition(pos),
99 4077 : myRadius(radius),
100 4077 : myTimeThreshold(timeThreshold),
101 12231 : myHaveParkProbs(false) {
102 4077 : myInstances[id] = this;
103 : // build actors
104 9468 : for (const MSEdge* const e : edges) {
105 5391 : if (MSGlobals::gUseMesoSim) {
106 777 : MSGlobals::gMesoNet->getSegmentForEdge(*e)->addDetector(this);
107 : }
108 11449 : for (MSLane* const lane : e->getLanes()) {
109 6058 : lane->addMoveReminder(this);
110 : }
111 : }
112 4077 : if (off) {
113 1 : setUserMode(true);
114 1 : setUserUsageProbability(0);
115 : }
116 8154 : const std::vector<std::string> vt = StringTokenizer(vTypes).getVector();
117 : myVehicleTypes.insert(vt.begin(), vt.end());
118 : if (myPosition == Position::INVALID) {
119 3615 : myPosition = edges.front()->getLanes()[0]->getShape()[0];
120 : }
121 4077 : }
122 :
123 :
124 7389 : MSTriggeredRerouter::~MSTriggeredRerouter() {
125 : myInstances.erase(getID());
126 11462 : }
127 :
128 :
129 : // ------------ loading begin
130 : void
131 19366 : MSTriggeredRerouter::myStartElement(int element,
132 : const SUMOSAXAttributes& attrs) {
133 19366 : if (element == SUMO_TAG_INTERVAL) {
134 3934 : bool ok = true;
135 3934 : myParsedRerouteInterval = RerouteInterval();
136 3934 : myParsedRerouteInterval.begin = attrs.getOptSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok, -1);
137 3934 : myParsedRerouteInterval.end = attrs.getOptSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok, SUMOTime_MAX);
138 3934 : 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 19360 : 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 19360 : if (element == SUMO_TAG_CLOSING_REROUTE) {
175 : // by closing edge
176 1058 : const std::string& closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
177 1058 : MSEdge* const closedEdge = MSEdge::dictionary(closed_id);
178 1058 : if (closedEdge == nullptr) {
179 0 : throw ProcessError(TLF("rerouter '%': Edge '%' to close is not known.", getID(), closed_id));
180 : }
181 : bool ok;
182 1058 : const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
183 1058 : const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
184 1058 : const SUMOTime until = attrs.getOptSUMOTimeReporting(SUMO_ATTR_UNTIL, nullptr, ok, TIME2STEPS(-1));
185 1058 : SVCPermissions permissions = parseVehicleClasses(allow, disallow);
186 1058 : myParsedRerouteInterval.closed[closedEdge] = std::make_pair(permissions, STEPS2TIME(until));
187 : }
188 :
189 19360 : 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 19360 : if (element == SUMO_TAG_ROUTE_PROB_REROUTE) {
207 : // by explicit rerouting using routes
208 : // check if route exists
209 765 : std::string routeStr = attrs.getStringSecure(SUMO_ATTR_ID, "");
210 765 : if (routeStr == "") {
211 0 : throw ProcessError(TLF("rerouter '%': routeProbReroute has no alternative route id.", getID()));
212 : }
213 765 : ConstMSRoutePtr route = MSRoute::dictionary(routeStr);
214 765 : 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 765 : bool ok = true;
220 765 : double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
221 765 : if (!ok) {
222 0 : throw ProcessError();
223 : }
224 765 : if (prob < 0) {
225 0 : throw ProcessError(TLF("rerouter '%': Attribute 'probability' for alternative route '%' is negative (must not).", getID(), routeStr));
226 : }
227 : // add
228 1530 : myParsedRerouteInterval.routeProbs.add(route, prob);
229 : }
230 :
231 19360 : if (element == SUMO_TAG_PARKING_AREA_REROUTE) {
232 13056 : std::string parkingarea = attrs.getStringSecure(SUMO_ATTR_ID, "");
233 13056 : if (parkingarea == "") {
234 0 : throw ProcessError(TLF("rerouter '%': parkingAreaReroute requires a parkingArea id.", getID()));
235 : }
236 13056 : MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(parkingarea, SUMO_TAG_PARKING_AREA));
237 13056 : if (pa == nullptr) {
238 0 : throw ProcessError(TLF("rerouter '%': parkingArea '%' is not known.", getID(), parkingarea));
239 : }
240 : // get the probability to reroute
241 13056 : bool ok = true;
242 13056 : const double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
243 13056 : if (!ok) {
244 0 : throw ProcessError();
245 : }
246 13056 : if (prob < 0) {
247 0 : throw ProcessError(TLF("rerouter '%': Attribute 'probability' for parkingArea '%' is negative (must not).", getID(), parkingarea));
248 : }
249 13056 : const bool visible = attrs.getOpt<bool>(SUMO_ATTR_VISIBLE, getID().c_str(), ok, false);
250 : // add
251 13056 : myParsedRerouteInterval.parkProbs.add(std::make_pair(pa, visible), prob);
252 13056 : myHaveParkProbs = true;
253 : }
254 :
255 19360 : 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 19360 : 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 19360 : if (element == SUMO_TAG_STATION_REROUTE) {
314 : // for letting a train switch it's stopping place in case of conflict
315 45 : const std::string stopID = attrs.getStringSecure(SUMO_ATTR_ID, "");
316 45 : if (stopID == "") {
317 0 : throw ProcessError(TLF("rerouter '%': stationReroute requires a stopping place id.", getID()));
318 : }
319 45 : MSStoppingPlace* stop = MSNet::getInstance()->getStoppingPlace(stopID);
320 45 : if (stop == nullptr) {
321 0 : throw ProcessError(TLF("rerouter '%': stopping place '%' is not known.", getID(), stopID));
322 : }
323 45 : myParsedRerouteInterval.stopAlternatives.push_back(std::make_pair(stop, true));
324 : }
325 19360 : }
326 :
327 :
328 : void
329 23431 : MSTriggeredRerouter::myEndElement(int element) {
330 23431 : if (element == SUMO_TAG_INTERVAL) {
331 : // precompute permissionsAllowAll
332 : bool allowAll = true;
333 4286 : for (const auto& entry : myParsedRerouteInterval.closed) {
334 887 : allowAll = allowAll && entry.second.first == SVCAll;
335 : if (!allowAll) {
336 : break;
337 : }
338 : }
339 3928 : myParsedRerouteInterval.permissionsAllowAll = allowAll;
340 :
341 16981 : for (auto paVi : myParsedRerouteInterval.parkProbs.getVals()) {
342 13053 : dynamic_cast<MSParkingArea*>(paVi.first)->setNumAlternatives((int)myParsedRerouteInterval.parkProbs.getVals().size() - 1);
343 : }
344 3928 : 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 3928 : const SUMOTime closingBegin = myParsedRerouteInterval.begin;
353 3928 : const SUMOTime simBegin = string2time(OptionsCont::getOptions().getString("begin"));
354 3928 : 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 3928 : myIntervals.push_back(myParsedRerouteInterval);
360 3928 : myIntervals.back().id = (long long int)&myIntervals.back();
361 3928 : if (!(myParsedRerouteInterval.closed.empty() && myParsedRerouteInterval.closedLanes.empty())) {
362 1844 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
363 922 : new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), myParsedRerouteInterval.begin);
364 : }
365 : }
366 23431 : }
367 :
368 :
369 : // ------------ loading end
370 :
371 :
372 : SUMOTime
373 1061 : MSTriggeredRerouter::setPermissions(const SUMOTime currentTime) {
374 : bool updateVehicles = false;
375 2165 : for (const RerouteInterval& i : myIntervals) {
376 1104 : if (i.begin == currentTime && !(i.closed.empty() && i.closedLanes.empty()) /*&& i.permissions != SVCAll*/) {
377 1931 : for (const auto& settings : i.closed) {
378 2061 : 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 1038 : lane->setPermissions(settings.second.first, i.id);
381 : }
382 1023 : settings.first->rebuildAllowedLanes();
383 : updateVehicles = true;
384 : }
385 1057 : 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 1816 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
391 908 : new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), i.end);
392 : }
393 1104 : if (i.end == currentTime && !(i.closed.empty() && i.closedLanes.empty()) /*&& i.permissions != SVCAll*/) {
394 336 : for (auto settings : i.closed) {
395 311 : for (MSLane* lane : settings.first->getLanes()) {
396 156 : lane->resetPermissions(i.id);
397 : //std::cout << SIMTIME << " opening: intervalID=" << i.id << " lane=" << lane->getID() << " restore prevPerm=" << getVehicleClassNames(lane->getPermissions()) << "\n";
398 : }
399 155 : settings.first->rebuildAllowedLanes();
400 : updateVehicles = true;
401 : }
402 294 : for (std::pair<MSLane*, SVCPermissions> settings : i.closedLanes) {
403 113 : settings.first->resetPermissions(i.id);
404 113 : settings.first->getEdge().rebuildAllowedLanes();
405 : updateVehicles = true;
406 : }
407 : }
408 : }
409 1061 : if (updateVehicles) {
410 : // only vehicles on the affected lanes had their bestlanes updated so far
411 2135 : for (MSEdge* e : myEdges) {
412 : // also updates vehicles
413 1074 : e->rebuildAllowedTargets();
414 : }
415 : }
416 1061 : return 0;
417 : }
418 :
419 :
420 : const MSTriggeredRerouter::RerouteInterval*
421 1199083 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time, SUMOTrafficObject& obj) const {
422 1710544 : for (const RerouteInterval& ri : myIntervals) {
423 1213164 : if (ri.begin <= time && ri.end > time) {
424 : if (
425 : // destProbReroute
426 716234 : ri.edgeProbs.getOverallProb() > 0 ||
427 : // routeProbReroute
428 177544 : ri.routeProbs.getOverallProb() > 0 ||
429 : // parkingZoneReroute
430 787302 : ri.parkProbs.getOverallProb() > 0 ||
431 : // stationReroute
432 : ri.stopAlternatives.size() > 0) {
433 651751 : return &ri;
434 : }
435 67768 : if (!ri.closed.empty() || !ri.closedLanesAffected.empty() || !ri.overtakeLocations.empty()) {
436 67768 : const std::set<SUMOTrafficObject::NumericalID>& edgeIndices = obj.getUpcomingEdgeIDs();
437 135536 : if (affected(edgeIndices, ri.getClosedEdges())
438 67768 : || affected(edgeIndices, ri.closedLanesAffected)) {
439 49808 : return &ri;
440 : }
441 17960 : 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 318065 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time) const {
456 318087 : for (const RerouteInterval& ri : myIntervals) {
457 318065 : if (ri.begin <= time && ri.end > time) {
458 318043 : if (ri.edgeProbs.getOverallProb() != 0 || ri.routeProbs.getOverallProb() != 0 || ri.parkProbs.getOverallProb() != 0
459 318061 : || !ri.closed.empty() || !ri.closedLanesAffected.empty() || !ri.overtakeLocations.empty()) {
460 : return &ri;
461 : }
462 : }
463 : }
464 : return nullptr;
465 : }
466 :
467 :
468 : bool
469 674668 : MSTriggeredRerouter::notifyEnter(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
470 674668 : if (myAmOptional || myRadius != std::numeric_limits<double>::max()) {
471 : return true;
472 : }
473 674528 : return triggerRouting(tObject, reason);
474 : }
475 :
476 :
477 : bool
478 523989 : MSTriggeredRerouter::notifyMove(SUMOTrafficObject& veh, double /*oldPos*/,
479 : double /*newPos*/, double /*newSpeed*/) {
480 523989 : return triggerRouting(veh, NOTIFICATION_JUNCTION);
481 : }
482 :
483 :
484 : bool
485 19031 : MSTriggeredRerouter::notifyLeave(SUMOTrafficObject& /*veh*/, double /*lastPos*/,
486 : MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
487 19031 : return reason == NOTIFICATION_LANE_CHANGE;
488 : }
489 :
490 :
491 : bool
492 1199153 : MSTriggeredRerouter::triggerRouting(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason) {
493 1199153 : if (!applies(tObject)) {
494 : return false;
495 : }
496 1199083 : 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 1199083 : const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
501 1199083 : const MSTriggeredRerouter::RerouteInterval* const rerouteDef = getCurrentReroute(now, tObject);
502 1199083 : if (rerouteDef == nullptr) {
503 : return true; // an active interval could appear later
504 : }
505 701703 : const double prob = myAmInUserMode ? myUserProbability : myProbability;
506 701703 : 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 701414 : if (myTimeThreshold > 0 && MAX2(tObject.getWaitingTime(), tObject.getWaitingTime(true)) < myTimeThreshold) {
510 : return true; // waiting time may be reached later
511 : }
512 694977 : 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 677695 : const bool hasReroutingDevice = tObject.getDevice(typeid(MSDevice_Routing)) != nullptr;
517 677695 : if (rerouteDef->closedLanes.size() > 0 && !hasReroutingDevice) {
518 : return true; // an active interval could appear later
519 : }
520 637684 : 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 637684 : if (rerouteDef->parkProbs.getOverallProb() > 0) {
528 : #ifdef HAVE_FOX
529 104474 : ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
530 : #endif
531 104474 : if (!tObject.isVehicle()) {
532 : return false;
533 : }
534 : SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
535 104409 : bool newDestination = false;
536 : ConstMSEdgeVector newRoute;
537 104409 : MSParkingArea* oldParkingArea = veh.getNextParkingArea();
538 104409 : MSParkingArea* newParkingArea = rerouteParkingArea(rerouteDef, veh, newDestination, newRoute);
539 104409 : if (newParkingArea != nullptr) {
540 : // adapt plans of any riders
541 28997 : for (MSTransportable* p : veh.getPersons()) {
542 40 : p->rerouteParkingArea(oldParkingArea, newParkingArea);
543 : }
544 :
545 28957 : 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 12890 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->getClosed())
556 57914 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->getClosed());
557 28957 : const double routeCost = router.recomputeCosts(newRoute, &veh, MSNet::getInstance()->getCurrentTimeStep());
558 28957 : ConstMSEdgeVector prevEdges(veh.getCurrentRouteEdge(), veh.getRoute().end());
559 28957 : resetClosedEdges(hasReroutingDevice, veh);
560 28957 : const double previousCost = router.recomputeCosts(prevEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
561 28957 : const double savings = previousCost - routeCost;
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 28957 : if (veh.replaceParkingArea(newParkingArea, errorMsg)) {
569 57914 : veh.replaceRouteEdges(newRoute, routeCost, savings, getID() + ":" + toString(SUMO_TAG_PARKING_AREA_REROUTE), false, false, false);
570 28957 : if (oldParkingArea->isReservable()) {
571 15 : oldParkingArea->removeSpaceReservation(&veh);
572 : }
573 28957 : if (newParkingArea->isReservable()) {
574 15 : 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 28957 : } else {
582 75452 : if (oldParkingArea && oldParkingArea->isReservable()) {
583 15 : oldParkingArea->addSpaceReservation(&veh);
584 : }
585 : }
586 : return false;
587 104409 : }
588 533210 : 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 533066 : if (rerouteDef->stopAlternatives.size() > 0) {
658 : // somewhat similar to parkProbs but taking into account public transport schedule
659 15 : if (!tObject.isVehicle()) {
660 : return false;
661 : }
662 15 : checkStopSwitch(static_cast<MSBaseVehicle&>(tObject), rerouteDef);
663 : }
664 : // get rerouting params
665 533066 : 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 533066 : if (newRoute != nullptr) {
668 : #ifdef DEBUG_REROUTER
669 : if (DEBUGCOND(tObject)) {
670 : std::cout << " replacedRoute from routeDist " << newRoute->getID() << "\n";
671 : }
672 : #endif
673 527047 : tObject.replaceRoute(newRoute, getID());
674 527044 : 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 6022 : const MSEdgeVector closedEdges = rerouteDef->getClosedEdges();
680 6022 : 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 6022 : if (closedEdges.empty() || destUnreachable || rerouteDef->isVia) {
685 4176 : newEdge = rerouteDef->edgeProbs.getOverallProb() > 0 ? rerouteDef->edgeProbs.get() : lastEdge;
686 : assert(newEdge != nullptr);
687 4176 : if (newEdge == &mySpecialDest_terminateRoute) {
688 : keepDestination = true;
689 55 : newEdge = tObject.getEdge();
690 55 : newArrivalPos = tObject.getPositionOnLane(); // instant arrival
691 4121 : } else if (newEdge == &mySpecialDest_keepDestination || newEdge == lastEdge) {
692 1577 : 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 6022 : MSEdgeVector closed = rerouteDef->getClosedEdges();
707 6022 : Prohibitions prohibited = rerouteDef->getClosed();
708 7868 : if (rerouteDef->closed.empty() || destUnreachable || rerouteDef->isVia || affected(tObject.getUpcomingEdgeIDs(), closed)) {
709 5945 : if (tObject.isVehicle()) {
710 : SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
711 4475 : ConstMSEdgeVector prevEdges = veh.getRoute().getEdges();
712 4475 : const bool canChangeDest = rerouteDef->edgeProbs.getOverallProb() > 0;
713 : MSVehicleRouter& router = hasReroutingDevice
714 4475 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), prohibited)
715 1790 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), prohibited);
716 4475 : bool ok = veh.reroute(now, getID(), router, false, false, canChangeDest, newEdge);
717 4472 : if (!ok && !keepDestination && canChangeDest) {
718 : // destination unreachable due to closed intermediate edges. pick among alternative targets
719 82 : RandomDistributor<MSEdge*> edgeProbs2 = rerouteDef->edgeProbs;
720 82 : edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
721 152 : while (!ok && edgeProbs2.getVals().size() > 0) {
722 110 : newEdge = edgeProbs2.get();
723 110 : edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
724 110 : if (newEdge == &mySpecialDest_terminateRoute) {
725 42 : newEdge = veh.getEdge();
726 42 : newArrivalPos = veh.getPositionOnLane(); // instant arrival
727 : }
728 110 : if (newEdge == &mySpecialDest_keepDestination && !rerouteDef->permissionsAllowAll) {
729 : newEdge = lastEdge;
730 : break;
731 : }
732 70 : ok = veh.reroute(now, getID(), router, false, false, true, newEdge);
733 : }
734 :
735 : }
736 4472 : resetClosedEdges(hasReroutingDevice, tObject);
737 4472 : if (ok) {
738 : // since the old route was closed, savings would be infinite. This isn't useful
739 4048 : const double previousCost = router.recomputeCosts(prevEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
740 4048 : const double savings = previousCost - veh.getRoute().getCosts();
741 4048 : const_cast<MSRoute&>(veh.getRoute()).setSavings(savings);
742 : }
743 4472 : if (!rerouteDef->isVia) {
744 : #ifdef DEBUG_REROUTER
745 : if (DEBUGCOND(tObject)) std::cout << " rerouting: newDest=" << newEdge->getID()
746 : << " newEdges=" << toString(edges)
747 : << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
748 : << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->getClosedEdges()) << "\n";
749 : #endif
750 4472 : if (ok && newArrivalPos != -1) {
751 : // must be called here because replaceRouteEdges may also set the arrivalPos
752 86 : veh.setArrivalPos(newArrivalPos);
753 : }
754 :
755 : }
756 4475 : } else {
757 : // person rerouting here
758 : MSTransportableRouter& router = hasReroutingDevice
759 1470 : ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), prohibited)
760 1470 : : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, prohibited);
761 4410 : const bool success = router.compute(tObject.getEdge(), newEdge, tObject.getPositionOnLane(), "",
762 1470 : rerouteDef->isVia ? newEdge->getLength() / 2. : tObject.getParameter().arrivalPos, "",
763 1470 : tObject.getMaxSpeed(), nullptr, tObject.getVTypeParameter(), 0, now, items);
764 1470 : if (!rerouteDef->isVia) {
765 700 : if (success) {
766 1400 : for (const MSTransportableRouter::TripItem& it : items) {
767 700 : if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
768 : edges.pop_back();
769 : }
770 700 : edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
771 700 : if (!edges.empty()) {
772 700 : static_cast<MSPerson&>(tObject).replaceWalk(edges, tObject.getPositionOnLane(), 0, 1);
773 : }
774 : }
775 : } else {
776 : // maybe the pedestrian model still finds a way (JuPedSim)
777 0 : static_cast<MSPerson&>(tObject).replaceWalk({tObject.getEdge(), newEdge}, tObject.getPositionOnLane(), 0, 1);
778 : }
779 : }
780 : }
781 5942 : if (!prohibited.empty()) {
782 1851 : resetClosedEdges(hasReroutingDevice, tObject);
783 : }
784 : }
785 : // it was only a via so calculate the remaining part
786 6019 : if (rerouteDef->isVia) {
787 770 : if (tObject.isVehicle()) {
788 : SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
789 0 : if (!edges.empty()) {
790 : edges.pop_back();
791 : }
792 : MSVehicleRouter& router = hasReroutingDevice
793 0 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), prohibited)
794 0 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), prohibited);
795 0 : router.compute(newEdge, lastEdge, &veh, now, edges);
796 0 : const double routeCost = router.recomputeCosts(edges, &veh, now);
797 : hasReroutingDevice
798 0 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass())
799 0 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
800 0 : const bool useNewRoute = veh.replaceRouteEdges(edges, routeCost, 0, getID());
801 : #ifdef DEBUG_REROUTER
802 : if (DEBUGCOND(tObject)) std::cout << " rerouting: newDest=" << newEdge->getID()
803 : << " newEdges=" << toString(edges)
804 : << " useNewRoute=" << useNewRoute << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
805 : << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->getClosedEdges()) << "\n";
806 : #endif
807 0 : if (useNewRoute && newArrivalPos != -1) {
808 : // must be called here because replaceRouteEdges may also set the arrivalPos
809 0 : veh.setArrivalPos(newArrivalPos);
810 : }
811 : } else {
812 : // person rerouting here
813 770 : bool success = !items.empty();
814 770 : if (success) {
815 : MSTransportableRouter& router = hasReroutingDevice
816 770 : ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), prohibited)
817 770 : : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, prohibited);
818 2310 : success = router.compute(newEdge, lastEdge, newEdge->getLength() / 2., "",
819 770 : tObject.getParameter().arrivalPos, "",
820 770 : tObject.getMaxSpeed(), nullptr, tObject.getVTypeParameter(), 0, now, items);
821 : }
822 770 : if (success) {
823 2310 : for (const MSTransportableRouter::TripItem& it : items) {
824 1540 : if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
825 : edges.pop_back();
826 : }
827 1540 : edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
828 : }
829 770 : if (!edges.empty()) {
830 770 : static_cast<MSPerson&>(tObject).replaceWalk(edges, tObject.getPositionOnLane(), 0, 1);
831 : }
832 : } else {
833 : // maybe the pedestrian model still finds a way (JuPedSim)
834 3 : static_cast<MSPerson&>(tObject).replaceWalk({tObject.getEdge(), newEdge, lastEdge}, tObject.getPositionOnLane(), 0, 1);
835 : }
836 : }
837 770 : if (!prohibited.empty()) {
838 0 : resetClosedEdges(hasReroutingDevice, tObject);
839 : }
840 : }
841 : return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
842 6031 : }
843 :
844 :
845 : void
846 1 : MSTriggeredRerouter::setUserMode(bool val) {
847 1 : myAmInUserMode = val;
848 1 : }
849 :
850 :
851 : void
852 1 : MSTriggeredRerouter::setUserUsageProbability(double prob) {
853 1 : myUserProbability = prob;
854 1 : }
855 :
856 :
857 : bool
858 0 : MSTriggeredRerouter::inUserMode() const {
859 0 : return myAmInUserMode;
860 : }
861 :
862 :
863 : double
864 5483 : MSTriggeredRerouter::getProbability() const {
865 5483 : return myAmInUserMode ? myUserProbability : myProbability;
866 : }
867 :
868 :
869 : double
870 0 : MSTriggeredRerouter::getUserProbability() const {
871 0 : return myUserProbability;
872 : }
873 :
874 :
875 : double
876 97101 : MSTriggeredRerouter::getStoppingPlaceOccupancy(MSStoppingPlace* sp, const SUMOVehicle* veh) {
877 : return (sp->getElement() == SUMO_TAG_PARKING_AREA
878 97101 : ? (double)dynamic_cast<MSParkingArea*>(sp)->getOccupancyIncludingRemoteReservations(veh)
879 42 : : (double)sp->getStoppedVehicles().size());
880 : }
881 :
882 :
883 : double
884 93661 : MSTriggeredRerouter::getLastStepStoppingPlaceOccupancy(MSStoppingPlace* sp, const SUMOVehicle* veh) {
885 : return (sp->getElement() == SUMO_TAG_PARKING_AREA
886 93661 : ? (double)dynamic_cast<MSParkingArea*>(sp)->getLastStepOccupancyIncludingRemoteReservations(veh)
887 42 : : (double)sp->getStoppedVehicles().size());
888 : }
889 :
890 :
891 : double
892 277183 : MSTriggeredRerouter::getStoppingPlaceCapacity(MSStoppingPlace* sp) {
893 : if (myBlockedStoppingPlaces.count(sp) == 0) {
894 : return (double)(sp->getElement() == SUMO_TAG_PARKING_AREA
895 277167 : ? dynamic_cast<MSParkingArea*>(sp)->getCapacity()
896 : // assume only one vehicle at a time (for stationReroute)
897 : : 1.);
898 : } else {
899 : return 0.;
900 : }
901 : }
902 :
903 :
904 : void
905 89657 : MSTriggeredRerouter::rememberBlockedStoppingPlace(SUMOVehicle& veh, const MSStoppingPlace* parkingArea, bool blocked) {
906 89657 : veh.rememberBlockedParkingArea(parkingArea, blocked);
907 89657 : }
908 :
909 :
910 : void
911 132358 : MSTriggeredRerouter::rememberStoppingPlaceScore(SUMOVehicle& veh, MSStoppingPlace* parkingArea, const std::string& score) {
912 132358 : veh.rememberParkingAreaScore(parkingArea, score);
913 132358 : }
914 :
915 :
916 : void
917 29773 : MSTriggeredRerouter::resetStoppingPlaceScores(SUMOVehicle& veh) {
918 29773 : veh.resetParkingAreaScores();
919 29773 : }
920 :
921 :
922 : SUMOTime
923 72007 : MSTriggeredRerouter::sawBlockedStoppingPlace(SUMOVehicle& veh, MSStoppingPlace* parkingArea, bool local) {
924 72007 : return veh.sawBlockedParkingArea(parkingArea, local);
925 : }
926 :
927 :
928 : int
929 69132 : MSTriggeredRerouter::getNumberStoppingPlaceReroutes(SUMOVehicle& veh) {
930 69132 : return veh.getNumberParkingReroutes();
931 : }
932 :
933 :
934 : void
935 29773 : MSTriggeredRerouter::setNumberStoppingPlaceReroutes(SUMOVehicle& veh, int value) {
936 29773 : veh.setNumberParkingReroutes(value);
937 29773 : }
938 :
939 :
940 : MSParkingArea*
941 104409 : MSTriggeredRerouter::rerouteParkingArea(const MSTriggeredRerouter::RerouteInterval* rerouteDef,
942 : SUMOVehicle& veh, bool& newDestination, ConstMSEdgeVector& newRoute) {
943 104409 : MSStoppingPlace* destStoppingPlace = veh.getNextParkingArea();
944 104409 : if (destStoppingPlace == nullptr) {
945 : // not driving towards the right type of stop
946 : return nullptr;
947 : }
948 : std::vector<StoppingPlaceVisible> parks;
949 295815 : for (auto cand : rerouteDef->parkProbs.getVals()) {
950 202071 : if (cand.first->accepts(&veh)) {
951 201391 : parks.push_back(cand);
952 : }
953 : }
954 : StoppingPlaceParamMap_t addInput = {};
955 187488 : return dynamic_cast<MSParkingArea*>(rerouteStoppingPlace(destStoppingPlace, parks, rerouteDef->parkProbs.getProbs(), veh, newDestination, newRoute, addInput, rerouteDef->getClosed()));
956 93744 : }
957 :
958 :
959 : std::pair<const SUMOVehicle*, MSRailSignal*>
960 183 : MSTriggeredRerouter::overtakingTrain(const SUMOVehicle& veh,
961 : ConstMSEdgeVector::const_iterator mainStart,
962 : const OvertakeLocation& oloc,
963 : double& netSaving) {
964 183 : const ConstMSEdgeVector& route = veh.getRoute().getEdges();
965 : const MSEdgeVector& main = oloc.main;
966 183 : const double vMax = veh.getMaxSpeed();
967 366 : const double prio = veh.getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".prio", false, DEFAULT_PRIO_OVERTAKEN, false);
968 183 : MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
969 437 : for (MSVehicleControl::constVehIt it_veh = c.loadedVehBegin(); it_veh != c.loadedVehEnd(); ++it_veh) {
970 307 : const MSBaseVehicle* veh2 = dynamic_cast<const MSBaseVehicle*>((*it_veh).second);
971 307 : if (veh2->isOnRoad() && veh2->getMaxSpeed() > vMax) {
972 93 : const double arrivalDelay = veh2->getStopArrivalDelay();
973 182 : const double delay = MAX2(veh2->getStopDelay(), arrivalDelay == INVALID_DOUBLE ? 0 : arrivalDelay);
974 279 : if (delay > veh2->getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".maxDelay", false, DEFAULT_MAXDELAY, false)) {
975 : continue;
976 : }
977 89 : const ConstMSEdgeVector& route2 = veh2->getRoute().getEdges();
978 : auto itOnMain2 = route2.end();
979 : int mainIndex = 0;
980 110 : for (const MSEdge* m : main) {
981 105 : itOnMain2 = std::find(veh2->getCurrentRouteEdge(), route2.end(), m);
982 105 : if (itOnMain2 != route2.end()) {
983 : break;
984 : }
985 21 : mainIndex++;
986 : }
987 89 : if (itOnMain2 != route2.end() && itOnMain2 > veh2->getCurrentRouteEdge()) {
988 : auto itOnMain = mainStart + mainIndex;
989 : double timeToMain = 0;
990 371 : for (auto it = veh.getCurrentRouteEdge(); it != itOnMain; it++) {
991 290 : timeToMain += (*it)->getMinimumTravelTime(&veh);
992 : }
993 : // veh2 may be anywhere on the current edge so we have to discount
994 81 : double timeToMain2 = -veh2->getEdge()->getMinimumTravelTime(veh2) * veh2->getPositionOnLane() / veh2->getEdge()->getLength();
995 : double timeToLastSignal2 = timeToMain2;
996 562 : for (auto it = veh2->getCurrentRouteEdge(); it != itOnMain2; it++) {
997 481 : timeToMain2 += (*it)->getMinimumTravelTime(veh2);
998 481 : auto signal = getRailSignal(*it);
999 481 : if (signal) {
1000 : timeToLastSignal2 = timeToMain2;
1001 : #ifdef DEBUG_OVERTAKING
1002 : std::cout << " lastBeforeMain2 " << signal->getID() << "\n";
1003 : #endif
1004 : }
1005 : }
1006 : double exitMainTime = timeToMain;
1007 : double exitMainBlockTime2 = timeToMain2;
1008 : double commonTime = 0;
1009 : double commonTime2 = 0;
1010 : int nCommon = 0;
1011 : auto exitMain2 = itOnMain2;
1012 : const MSRailSignal* firstAfterMain = nullptr;
1013 : const MSEdge* common = nullptr;
1014 81 : double vMinCommon = (*itOnMain)->getVehicleMaxSpeed(&veh);
1015 81 : double vMinCommon2 = (*itOnMain2)->getVehicleMaxSpeed(veh2);
1016 : while (itOnMain2 != route2.end()
1017 794 : && itOnMain != route.end()
1018 1657 : && *itOnMain == *itOnMain2) {
1019 : common = *itOnMain;
1020 785 : commonTime += common->getMinimumTravelTime(&veh);
1021 785 : commonTime2 += common->getMinimumTravelTime(veh2);
1022 785 : vMinCommon = MIN2(vMinCommon, common->getVehicleMaxSpeed(&veh));
1023 785 : vMinCommon2 = MIN2(vMinCommon2, common->getVehicleMaxSpeed(veh2));
1024 785 : const bool onMain = nCommon < (int)main.size() - mainIndex;
1025 785 : if (onMain) {
1026 240 : exitMainTime = timeToMain + commonTime;
1027 : }
1028 785 : if (firstAfterMain == nullptr) {
1029 480 : exitMainBlockTime2 = timeToMain2 + commonTime2;
1030 : }
1031 785 : auto signal = getRailSignal(common);
1032 785 : if (signal) {
1033 318 : if (!onMain && firstAfterMain == nullptr) {
1034 : firstAfterMain = signal;
1035 : #ifdef DEBUG_OVERTAKING
1036 : std::cout << " firstAfterMain " << signal->getID() << "\n";
1037 : #endif
1038 : }
1039 : }
1040 785 : nCommon++;
1041 : itOnMain++;
1042 : itOnMain2++;
1043 : }
1044 81 : const double vMaxLast = common->getVehicleMaxSpeed(&veh);
1045 81 : const double vMaxLast2 = common->getVehicleMaxSpeed(veh2);
1046 81 : commonTime += veh.getLength() / vMaxLast;
1047 81 : exitMainBlockTime2 += veh2->getLength() / vMaxLast2;
1048 81 : exitMain2 += MIN2(nCommon, (int)main.size() - mainIndex);
1049 81 : double timeLoss2 = MAX2(0.0, timeToMain + veh.getLength() / oloc.siding.front()->getVehicleMaxSpeed(&veh) - timeToLastSignal2);
1050 81 : const double saving = timeToMain + commonTime - (timeToMain2 + commonTime2) - timeLoss2;
1051 81 : const double loss = exitMainBlockTime2 - exitMainTime;
1052 162 : const double prio2 = veh2->getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".prio", false, DEFAULT_PRIO_OVERTAKER, false);
1053 : // losses from acceleration after stopping at a signal
1054 81 : const double accelTimeLoss = loss > 0 ? 0.5 * vMinCommon / veh.getVehicleType().getCarFollowModel().getMaxAccel() : 0;
1055 81 : const double accelTimeLoss2 = timeLoss2 > 0 ? 0.5 * vMinCommon2 / veh2->getVehicleType().getCarFollowModel().getMaxAccel() : 0;
1056 81 : netSaving = prio2 * (saving - accelTimeLoss2) - prio * (loss + accelTimeLoss);
1057 : #ifdef DEBUG_OVERTAKING
1058 : std::cout << SIMTIME << " veh=" << veh.getID() << " veh2=" << veh2->getID()
1059 : << " sidingStart=" << oloc.siding.front()->getID()
1060 : << " ttm=" << timeToMain << " ttm2=" << timeToMain2
1061 : << " nCommon=" << nCommon << " cT=" << commonTime << " cT2=" << commonTime2
1062 : << " em=" << exitMainTime << " emb2=" << exitMainBlockTime2
1063 : << " ttls2=" << timeToLastSignal2
1064 : << " saving=" << saving << " loss=" << loss
1065 : << " atl=" << accelTimeLoss << " atl2=" << accelTimeLoss2 << " tl2=" << timeLoss2
1066 : << " prio=" << prio << " prio2=" << prio2 << " netSaving=" << netSaving << "\n";
1067 : #endif
1068 81 : if (netSaving > oloc.minSaving) {
1069 53 : MSRailSignal* s = findSignal(veh2->getCurrentRouteEdge(), exitMain2);
1070 53 : if (s != nullptr) {
1071 53 : return std::make_pair(veh2, s);
1072 : }
1073 : }
1074 : }
1075 : }
1076 : }
1077 130 : return std::make_pair(nullptr, nullptr);
1078 : }
1079 :
1080 :
1081 : void
1082 15 : MSTriggeredRerouter::checkStopSwitch(MSBaseVehicle& ego, const MSTriggeredRerouter::RerouteInterval* def) {
1083 : myBlockedStoppingPlaces.clear();
1084 : #ifdef DEBUG_REROUTER
1085 : std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << "\n";
1086 : #endif
1087 15 : if (!ego.hasStops()) {
1088 1 : return;
1089 : }
1090 15 : const MSStop& stop = ego.getNextStop();
1091 15 : if (stop.reached || stop.joinTriggered || (stop.pars.arrival < 0 && stop.pars.until < 0)) {
1092 : return;
1093 : }
1094 15 : MSStoppingPlace* cur = nullptr;
1095 30 : for (MSStoppingPlace* sp : stop.getPlaces()) {
1096 15 : for (auto item : def->stopAlternatives) {
1097 15 : if (sp == item.first) {
1098 15 : cur = sp;
1099 15 : break;
1100 : }
1101 : }
1102 15 : }
1103 15 : if (cur == nullptr) {
1104 : return;
1105 : }
1106 15 : std::vector<const SUMOVehicle*> stopped = cur->getStoppedVehicles();
1107 : #ifdef DEBUG_REROUTER
1108 : std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopped=" << toString(stopped) << "\n";
1109 : #endif
1110 : SUMOTime stoppedDuration = -1;
1111 15 : if (stopped.empty()) {
1112 : /// look upstream for vehicles that stop on this lane before ego arrives
1113 9 : const MSLane& stopLane = cur->getLane();
1114 9 : MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
1115 28 : for (MSVehicleControl::constVehIt it_veh = c.loadedVehBegin(); it_veh != c.loadedVehEnd(); ++it_veh) {
1116 19 : const MSBaseVehicle* veh = dynamic_cast<const MSBaseVehicle*>((*it_veh).second);
1117 19 : if (veh->isOnRoad() && veh->hasStops()) {
1118 19 : const MSStop& vehStop = veh->getNextStop();
1119 19 : if (vehStop.pars.lane == stopLane.getID()) {
1120 : myBlockedStoppingPlaces.insert(cur);
1121 12 : if (veh->isStopped()) {
1122 : // stopped somewhere else on the same lane
1123 3 : stoppedDuration = MAX3((SUMOTime)0, stoppedDuration, veh->getStopDuration());
1124 : } else {
1125 9 : std::pair<double, double> timeDist = veh->estimateTimeToNextStop();
1126 9 : SUMOTime timeTo = TIME2STEPS(timeDist.first);
1127 9 : stoppedDuration = MAX3((SUMOTime)0, stoppedDuration, timeTo + vehStop.getMinDuration(SIMSTEP + timeTo));
1128 : }
1129 : }
1130 : }
1131 : }
1132 : } else {
1133 : stoppedDuration = 0;
1134 12 : for (const SUMOVehicle* veh : cur->getStoppedVehicles()) {
1135 6 : stoppedDuration = MAX2(stoppedDuration, veh->getStopDuration());
1136 6 : }
1137 : }
1138 15 : if (stoppedDuration < 0) {
1139 : return;
1140 : }
1141 : /// @todo: consider time for conflict veh to leave the block
1142 15 : const SUMOTime stopFree = SIMSTEP + stoppedDuration;
1143 15 : const SUMOTime scheduledArrival = stop.pars.arrival >= 0 ? stop.pars.arrival : stop.pars.until - stop.pars.duration;
1144 : #ifdef DEBUG_REROUTER
1145 : std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopFree=" << stopFree << " scheduledArrival=" << time2string(scheduledArrival) << "\n";
1146 : #endif
1147 15 : if (stopFree < scheduledArrival) {
1148 : // no conflict according to the schedule
1149 : return;
1150 : }
1151 14 : const SUMOTime estimatedArrival = SIMSTEP + (stop.pars.arrival >= 0
1152 14 : ? TIME2STEPS(ego.getStopArrivalDelay())
1153 16 : : TIME2STEPS(ego.getStopDelay()) - stop.pars.duration);
1154 : #ifdef DEBUG_REROUTER
1155 : std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopFree=" << stopFree << " estimatedArrival=" << time2string(estimatedArrival) << "\n";
1156 : #endif
1157 14 : if (stopFree < estimatedArrival) {
1158 : // no conflict when considering current delay
1159 : return;
1160 : }
1161 14 : const std::vector<double> probs(def->stopAlternatives.size(), 1.);
1162 : StoppingPlaceParamMap_t scores = {};
1163 : bool newDestination;
1164 : ConstMSEdgeVector newRoute;
1165 : // @todo: consider future conflicts caused by rerouting
1166 : // @todo: reject alternatives with large detour
1167 14 : const MSStoppingPlace* alternative = rerouteStoppingPlace(nullptr, def->stopAlternatives, probs, ego, newDestination, newRoute, scores);
1168 : #ifdef DEBUG_REROUTER
1169 : std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " alternative=" << Named::getIDSecure(alternative) << "\n";
1170 : #endif
1171 14 : if (alternative != nullptr) {
1172 : // @todo adapt plans of any riders
1173 : //for (MSTransportable* p : ego.getPersons()) {
1174 : // p->rerouteParkingArea(ego.getNextParkingArea(), newParkingArea);
1175 : //}
1176 :
1177 14 : if (newDestination && ego.getParameter().arrivalPosProcedure != ArrivalPosDefinition::DEFAULT) {
1178 : // update arrival parameters
1179 0 : SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
1180 0 : *newParameter = ego.getParameter();
1181 0 : newParameter->arrivalPosProcedure = ArrivalPosDefinition::GIVEN;
1182 0 : newParameter->arrivalPos = alternative->getEndLanePosition();
1183 0 : ego.replaceParameter(newParameter);
1184 : }
1185 :
1186 14 : SUMOVehicleParameter::Stop newStop = stop.pars;
1187 14 : newStop.lane = alternative->getLane().getID();
1188 14 : newStop.startPos = alternative->getBeginLanePosition();
1189 14 : newStop.endPos = alternative->getEndLanePosition();
1190 14 : switch (alternative->getElement()) {
1191 0 : case SUMO_TAG_PARKING_AREA:
1192 : newStop.parkingarea = alternative->getID();
1193 : break;
1194 0 : case SUMO_TAG_CONTAINER_STOP:
1195 : newStop.containerstop = alternative->getID();
1196 : break;
1197 0 : case SUMO_TAG_CHARGING_STATION:
1198 : newStop.chargingStation = alternative->getID();
1199 : break;
1200 0 : case SUMO_TAG_OVERHEAD_WIRE_SEGMENT:
1201 : newStop.overheadWireSegment = alternative->getID();
1202 : break;
1203 14 : case SUMO_TAG_BUS_STOP:
1204 : case SUMO_TAG_TRAIN_STOP:
1205 : default:
1206 : newStop.busstop = alternative->getID();
1207 : }
1208 : std::string errorMsg;
1209 28 : if (!ego.replaceStop(0, newStop, getID() + ":" + toString(SUMO_TAG_STATION_REROUTE), false, errorMsg)) {
1210 0 : WRITE_WARNING("Vehicle '" + ego.getID() + "' at rerouter '" + getID()
1211 : + "' could not perform stationReroute to '" + alternative->getID()
1212 : + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
1213 : }
1214 14 : }
1215 29 : }
1216 :
1217 :
1218 : MSRailSignal*
1219 152 : MSTriggeredRerouter::findSignal(ConstMSEdgeVector::const_iterator begin, ConstMSEdgeVector::const_iterator end) {
1220 152 : auto it = end;
1221 : do {
1222 : it--;
1223 304 : auto signal = getRailSignal(*it);
1224 304 : if (signal != nullptr) {
1225 152 : return signal;
1226 : }
1227 152 : } while (it != begin);
1228 : return nullptr;
1229 : }
1230 :
1231 :
1232 : MSRailSignal*
1233 1570 : MSTriggeredRerouter::getRailSignal(const MSEdge* edge) {
1234 1570 : if (edge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
1235 732 : for (const MSLink* link : edge->getLanes().front()->getLinkCont()) {
1236 732 : if (link->getTLLogic() != nullptr) {
1237 732 : return dynamic_cast<MSRailSignal*>(const_cast<MSTrafficLightLogic*>(link->getTLLogic()));
1238 : }
1239 : }
1240 : }
1241 : return nullptr;
1242 : }
1243 :
1244 : bool
1245 1199153 : MSTriggeredRerouter::applies(const SUMOTrafficObject& obj) const {
1246 1199153 : if (myVehicleTypes.empty() || myVehicleTypes.count(obj.getVehicleType().getOriginalID()) > 0) {
1247 1199083 : return true;
1248 : } else {
1249 140 : std::set<std::string> vTypeDists = MSNet::getInstance()->getVehicleControl().getVTypeDistributionMembership(obj.getVehicleType().getOriginalID());
1250 70 : for (auto vTypeDist : vTypeDists) {
1251 : if (myVehicleTypes.count(vTypeDist) > 0) {
1252 : return true;
1253 : }
1254 : }
1255 70 : return false;
1256 : }
1257 : }
1258 :
1259 :
1260 : bool
1261 130848 : MSTriggeredRerouter::affected(const std::set<SUMOTrafficObject::NumericalID>& edgeIndices, const MSEdgeVector& closed) {
1262 148994 : for (const MSEdge* const e : closed) {
1263 69867 : if (edgeIndices.count(e->getNumericalID()) > 0) {
1264 : return true;
1265 : }
1266 : }
1267 : return false;
1268 : }
1269 :
1270 :
1271 : void
1272 26120 : MSTriggeredRerouter::checkParkingRerouteConsistency() {
1273 : // if a parkingArea is a rerouting target, it should generally have a
1274 : // rerouter on its edge or vehicles will be stuck there once it's full.
1275 : // The user should receive a Warning in this case
1276 : std::set<MSEdge*> parkingRerouterEdges;
1277 : std::map<MSParkingArea*, std::string, ComparatorIdLess> targetedParkingArea; // paID -> targetingRerouter
1278 30172 : for (const auto& rr : myInstances) {
1279 : bool hasParkingReroute = false;
1280 7961 : for (const RerouteInterval& interval : rr.second->myIntervals) {
1281 3909 : if (interval.parkProbs.getOverallProb() > 0) {
1282 : hasParkingReroute = true;
1283 15258 : for (const StoppingPlaceVisible& pav : interval.parkProbs.getVals()) {
1284 26106 : targetedParkingArea[dynamic_cast<MSParkingArea*>(pav.first)] = rr.first;
1285 : }
1286 : }
1287 : }
1288 4052 : if (hasParkingReroute) {
1289 2205 : parkingRerouterEdges.insert(rr.second->myEdges.begin(), rr.second->myEdges.end());
1290 : }
1291 : }
1292 28967 : for (const auto& item : targetedParkingArea) {
1293 2847 : if (parkingRerouterEdges.count(&item.first->getLane().getEdge()) == 0) {
1294 1312 : WRITE_WARNINGF(TL("ParkingArea '%' is targeted by rerouter '%' but doesn't have its own rerouter. This may cause parking search to abort."),
1295 : item.first->getID(), item.second);
1296 : }
1297 : }
1298 26120 : }
1299 :
1300 :
1301 : void
1302 35316 : MSTriggeredRerouter::resetClosedEdges(bool hasReroutingDevice, const SUMOTrafficObject& o) {
1303 : // getRouterTT without prohibitions removes previous prohibitions
1304 35316 : if (o.isVehicle()) {
1305 : hasReroutingDevice
1306 70632 : ? MSRoutingEngine::getRouterTT(o.getRNGIndex(), o.getVClass())
1307 54747 : : MSNet::getInstance()->getRouterTT(o.getRNGIndex());
1308 : } else {
1309 : hasReroutingDevice
1310 0 : ? MSRoutingEngine::getIntermodalRouterTT(o.getRNGIndex())
1311 0 : : MSNet::getInstance()->getIntermodalRouter(o.getRNGIndex(), 0);
1312 : }
1313 35316 : }
1314 :
1315 : /****************************************************************************/
|