Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2025 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 3998 : MSTriggeredRerouter::MSTriggeredRerouter(const std::string& id,
88 : const MSEdgeVector& edges, double prob, bool off, bool optional,
89 3998 : SUMOTime timeThreshold, const std::string& vTypes, const Position& pos, const double radius) :
90 : Named(id),
91 : MSMoveReminder(id),
92 : MSStoppingPlaceRerouter("parking"),
93 3998 : myEdges(edges),
94 3998 : myProbability(prob),
95 3998 : myUserProbability(prob),
96 3998 : myAmInUserMode(false),
97 3998 : myAmOptional(optional),
98 3998 : myPosition(pos),
99 3998 : myRadius(radius),
100 3998 : myTimeThreshold(timeThreshold),
101 11994 : myHaveParkProbs(false) {
102 3998 : myInstances[id] = this;
103 : // build actors
104 9298 : for (const MSEdge* const e : edges) {
105 5300 : if (MSGlobals::gUseMesoSim) {
106 696 : MSGlobals::gMesoNet->getSegmentForEdge(*e)->addDetector(this);
107 : }
108 11303 : for (MSLane* const lane : e->getLanes()) {
109 6003 : lane->addMoveReminder(this);
110 : }
111 : }
112 3998 : if (off) {
113 1 : setUserMode(true);
114 1 : setUserUsageProbability(0);
115 : }
116 7996 : const std::vector<std::string> vt = StringTokenizer(vTypes).getVector();
117 : myVehicleTypes.insert(vt.begin(), vt.end());
118 : if (myPosition == Position::INVALID) {
119 3581 : myPosition = edges.front()->getLanes()[0]->getShape()[0];
120 : }
121 3998 : }
122 :
123 :
124 7279 : MSTriggeredRerouter::~MSTriggeredRerouter() {
125 : myInstances.erase(getID());
126 11273 : }
127 :
128 :
129 : // ------------ loading begin
130 : void
131 19510 : MSTriggeredRerouter::myStartElement(int element,
132 : const SUMOSAXAttributes& attrs) {
133 19510 : if (element == SUMO_TAG_INTERVAL) {
134 3791 : bool ok = true;
135 3791 : myParsedRerouteInterval = RerouteInterval();
136 3791 : myParsedRerouteInterval.begin = attrs.getOptSUMOTimeReporting(SUMO_ATTR_BEGIN, nullptr, ok, -1);
137 3791 : myParsedRerouteInterval.end = attrs.getOptSUMOTimeReporting(SUMO_ATTR_END, nullptr, ok, SUMOTime_MAX);
138 3791 : 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 19504 : if (element == SUMO_TAG_DEST_PROB_REROUTE) {
145 : // by giving probabilities of new destinations
146 : // get the destination edge
147 214 : std::string dest = attrs.getStringSecure(SUMO_ATTR_ID, "");
148 214 : if (dest == "") {
149 0 : throw ProcessError(TLF("rerouter '%': destProbReroute has no destination edge id.", getID()));
150 : }
151 214 : MSEdge* to = MSEdge::dictionary(dest);
152 214 : 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 214 : bool ok = true;
163 214 : double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
164 214 : if (!ok) {
165 0 : throw ProcessError();
166 : }
167 214 : if (prob < 0) {
168 0 : throw ProcessError(TLF("rerouter '%': Attribute 'probability' for destination '%' is negative (must not).", getID(), dest));
169 : }
170 : // add
171 214 : myParsedRerouteInterval.edgeProbs.add(to, prob);
172 : }
173 :
174 19504 : if (element == SUMO_TAG_CLOSING_REROUTE) {
175 : // by closing edge
176 926 : const std::string& closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
177 926 : MSEdge* const closedEdge = MSEdge::dictionary(closed_id);
178 926 : if (closedEdge == nullptr) {
179 0 : throw ProcessError(TLF("rerouter '%': Edge '%' to close is not known.", getID(), closed_id));
180 : }
181 : bool ok;
182 926 : const std::string allow = attrs.getOpt<std::string>(SUMO_ATTR_ALLOW, getID().c_str(), ok, "", false);
183 926 : const std::string disallow = attrs.getOpt<std::string>(SUMO_ATTR_DISALLOW, getID().c_str(), ok, "");
184 926 : const SUMOTime until = attrs.getOptSUMOTimeReporting(SUMO_ATTR_UNTIL, nullptr, ok, -1);
185 926 : SVCPermissions permissions = parseVehicleClasses(allow, disallow);
186 926 : myParsedRerouteInterval.closed[closedEdge] = std::make_pair(permissions, STEPS2TIME(until));
187 : }
188 :
189 19504 : if (element == SUMO_TAG_CLOSING_LANE_REROUTE) {
190 : // by closing lane
191 139 : std::string closed_id = attrs.getStringSecure(SUMO_ATTR_ID, "");
192 139 : MSLane* closedLane = MSLane::dictionary(closed_id);
193 139 : 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 139 : 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 139 : myParsedRerouteInterval.closedLanes[closedLane] = permissions;
204 : }
205 :
206 19504 : 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 19504 : if (element == SUMO_TAG_PARKING_AREA_REROUTE) {
232 13518 : std::string parkingarea = attrs.getStringSecure(SUMO_ATTR_ID, "");
233 13518 : if (parkingarea == "") {
234 0 : throw ProcessError(TLF("rerouter '%': parkingAreaReroute requires a parkingArea id.", getID()));
235 : }
236 13518 : MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(parkingarea, SUMO_TAG_PARKING_AREA));
237 13518 : if (pa == nullptr) {
238 0 : throw ProcessError(TLF("rerouter '%': parkingArea '%' is not known.", getID(), parkingarea));
239 : }
240 : // get the probability to reroute
241 13518 : bool ok = true;
242 13518 : const double prob = attrs.getOpt<double>(SUMO_ATTR_PROB, getID().c_str(), ok, 1.);
243 13518 : if (!ok) {
244 0 : throw ProcessError();
245 : }
246 13518 : if (prob < 0) {
247 0 : throw ProcessError(TLF("rerouter '%': Attribute 'probability' for parkingArea '%' is negative (must not).", getID(), parkingarea));
248 : }
249 13518 : const bool visible = attrs.getOpt<bool>(SUMO_ATTR_VISIBLE, getID().c_str(), ok, false);
250 : // add
251 13518 : myParsedRerouteInterval.parkProbs.add(std::make_pair(pa, visible), prob);
252 13518 : myHaveParkProbs = true;
253 : }
254 :
255 19504 : 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 19504 : 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 19504 : 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 19504 : }
326 :
327 :
328 : void
329 23496 : MSTriggeredRerouter::myEndElement(int element) {
330 23496 : if (element == SUMO_TAG_INTERVAL) {
331 : // precompute permissionsAllowAll
332 : bool allowAll = true;
333 4136 : for (const auto& entry : myParsedRerouteInterval.closed) {
334 765 : allowAll = allowAll && entry.second.first == SVCAll;
335 : if (!allowAll) {
336 : break;
337 : }
338 : }
339 3785 : myParsedRerouteInterval.permissionsAllowAll = allowAll;
340 :
341 17300 : for (auto paVi : myParsedRerouteInterval.parkProbs.getVals()) {
342 13515 : dynamic_cast<MSParkingArea*>(paVi.first)->setNumAlternatives((int)myParsedRerouteInterval.parkProbs.getVals().size() - 1);
343 : }
344 3785 : if (myParsedRerouteInterval.closedLanes.size() > 0) {
345 : // collect edges that are affect by a closed lane
346 : std::set<MSEdge*> affected;
347 223 : for (std::pair<MSLane*, SVCPermissions> settings : myParsedRerouteInterval.closedLanes) {
348 133 : affected.insert(&settings.first->getEdge());
349 : }
350 90 : myParsedRerouteInterval.closedLanesAffected.insert(myParsedRerouteInterval.closedLanesAffected.begin(), affected.begin(), affected.end());
351 : }
352 3785 : const SUMOTime closingBegin = myParsedRerouteInterval.begin;
353 3785 : const SUMOTime simBegin = string2time(OptionsCont::getOptions().getString("begin"));
354 3785 : if (closingBegin < simBegin && myParsedRerouteInterval.end > simBegin) {
355 : // interval started before simulation begin but is still active at
356 : // the start of the simulation
357 403 : myParsedRerouteInterval.begin = simBegin;
358 : }
359 3785 : myIntervals.push_back(myParsedRerouteInterval);
360 3785 : myIntervals.back().id = (long long int)&myIntervals.back();
361 3785 : if (!(myParsedRerouteInterval.closed.empty() && myParsedRerouteInterval.closedLanes.empty())) {
362 1598 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
363 799 : new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), myParsedRerouteInterval.begin);
364 : }
365 : }
366 23496 : }
367 :
368 :
369 : // ------------ loading end
370 :
371 :
372 : SUMOTime
373 944 : MSTriggeredRerouter::setPermissions(const SUMOTime currentTime) {
374 : bool updateVehicles = false;
375 1931 : for (const RerouteInterval& i : myIntervals) {
376 987 : if (i.begin == currentTime && !(i.closed.empty() && i.closedLanes.empty()) /*&& i.permissions != SVCAll*/) {
377 1700 : for (const auto& settings : i.closed) {
378 1821 : 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 918 : lane->setPermissions(settings.second.first, i.id);
381 : }
382 903 : settings.first->rebuildAllowedLanes();
383 : updateVehicles = true;
384 : }
385 944 : for (std::pair<MSLane*, SVCPermissions> settings : i.closedLanes) {
386 147 : settings.first->setPermissions(settings.second, i.id);
387 147 : settings.first->getEdge().rebuildAllowedLanes();
388 : updateVehicles = true;
389 : }
390 1594 : MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
391 797 : new WrappingCommand<MSTriggeredRerouter>(this, &MSTriggeredRerouter::setPermissions), i.end);
392 : }
393 987 : if (i.end == currentTime && !(i.closed.empty() && i.closedLanes.empty()) /*&& i.permissions != SVCAll*/) {
394 325 : for (auto settings : i.closed) {
395 301 : for (MSLane* lane : settings.first->getLanes()) {
396 151 : lane->resetPermissions(i.id);
397 : //std::cout << SIMTIME << " opening: intervalID=" << i.id << " lane=" << lane->getID() << " restore prevPerm=" << getVehicleClassNames(lane->getPermissions()) << "\n";
398 : }
399 150 : settings.first->rebuildAllowedLanes();
400 : updateVehicles = true;
401 : }
402 286 : for (std::pair<MSLane*, SVCPermissions> settings : i.closedLanes) {
403 111 : settings.first->resetPermissions(i.id);
404 111 : settings.first->getEdge().rebuildAllowedLanes();
405 : updateVehicles = true;
406 : }
407 : }
408 : }
409 944 : if (updateVehicles) {
410 : // only vehicles on the affected lanes had their bestlanes updated so far
411 1901 : for (MSEdge* e : myEdges) {
412 : // also updates vehicles
413 957 : e->rebuildAllowedTargets();
414 : }
415 : }
416 944 : return 0;
417 : }
418 :
419 :
420 : const MSTriggeredRerouter::RerouteInterval*
421 1176493 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time, SUMOTrafficObject& obj) const {
422 1684551 : for (const RerouteInterval& ri : myIntervals) {
423 1190574 : if (ri.begin <= time && ri.end > time) {
424 : if (
425 : // destProbReroute
426 696636 : ri.edgeProbs.getOverallProb() > 0 ||
427 : // routeProbReroute
428 161040 : ri.routeProbs.getOverallProb() > 0 ||
429 : // parkingZoneReroute
430 763780 : ri.parkProbs.getOverallProb() > 0 ||
431 : // stationReroute
432 : ri.stopAlternatives.size() > 0) {
433 635458 : return &ri;
434 : }
435 64155 : if (!ri.closed.empty() || !ri.closedLanesAffected.empty() || !ri.overtakeLocations.empty()) {
436 64155 : const std::set<SUMOTrafficObject::NumericalID>& edgeIndices = obj.getUpcomingEdgeIDs();
437 128310 : if (affected(edgeIndices, ri.getClosedEdges())
438 64155 : || affected(edgeIndices, ri.closedLanesAffected)) {
439 46914 : return &ri;
440 : }
441 17241 : 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 7915 : MSTriggeredRerouter::getCurrentReroute(SUMOTime time) const {
456 7932 : for (const RerouteInterval& ri : myIntervals) {
457 7915 : if (ri.begin <= time && ri.end > time) {
458 7898 : if (ri.edgeProbs.getOverallProb() != 0 || ri.routeProbs.getOverallProb() != 0 || ri.parkProbs.getOverallProb() != 0
459 7913 : || !ri.closed.empty() || !ri.closedLanesAffected.empty() || !ri.overtakeLocations.empty()) {
460 : return &ri;
461 : }
462 : }
463 : }
464 : return nullptr;
465 : }
466 :
467 :
468 : bool
469 658100 : MSTriggeredRerouter::notifyEnter(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
470 658100 : if (myAmOptional || myRadius != std::numeric_limits<double>::max()) {
471 : return true;
472 : }
473 657960 : return triggerRouting(tObject, reason);
474 : }
475 :
476 :
477 : bool
478 518377 : MSTriggeredRerouter::notifyMove(SUMOTrafficObject& veh, double /*oldPos*/,
479 : double /*newPos*/, double /*newSpeed*/) {
480 518377 : return triggerRouting(veh, NOTIFICATION_JUNCTION);
481 : }
482 :
483 :
484 : bool
485 18806 : MSTriggeredRerouter::notifyLeave(SUMOTrafficObject& /*veh*/, double /*lastPos*/,
486 : MSMoveReminder::Notification reason, const MSLane* /* enteredLane */) {
487 18806 : return reason == NOTIFICATION_LANE_CHANGE;
488 : }
489 :
490 :
491 : bool
492 1176563 : MSTriggeredRerouter::triggerRouting(SUMOTrafficObject& tObject, MSMoveReminder::Notification reason) {
493 1176563 : if (!applies(tObject)) {
494 : return false;
495 : }
496 1176493 : 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 1176493 : const SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
501 1176493 : const MSTriggeredRerouter::RerouteInterval* const rerouteDef = getCurrentReroute(now, tObject);
502 1176493 : if (rerouteDef == nullptr) {
503 : return true; // an active interval could appear later
504 : }
505 682516 : const double prob = myAmInUserMode ? myUserProbability : myProbability;
506 682516 : 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 682227 : if (myTimeThreshold > 0 && MAX2(tObject.getWaitingTime(), tObject.getWaitingTime(true)) < myTimeThreshold) {
510 : return true; // waiting time may be reached later
511 : }
512 675553 : 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 657682 : const bool hasReroutingDevice = tObject.getDevice(typeid(MSDevice_Routing)) != nullptr;
517 657682 : if (rerouteDef->closedLanes.size() > 0 && !hasReroutingDevice) {
518 : return true; // an active interval could appear later
519 : }
520 620232 : 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 620232 : if (rerouteDef->parkProbs.getOverallProb() > 0) {
528 : #ifdef HAVE_FOX
529 91656 : ScopedLocker<> lock(myNotificationMutex, MSGlobals::gNumSimThreads > 1);
530 : #endif
531 91656 : if (!tObject.isVehicle()) {
532 : return false;
533 : }
534 : SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
535 91591 : bool newDestination = false;
536 : ConstMSEdgeVector newRoute;
537 91591 : MSParkingArea* newParkingArea = rerouteParkingArea(rerouteDef, veh, newDestination, newRoute);
538 91591 : if (newParkingArea != nullptr) {
539 : // adapt plans of any riders
540 18300 : for (MSTransportable* p : veh.getPersons()) {
541 40 : p->rerouteParkingArea(veh.getNextParkingArea(), newParkingArea);
542 : }
543 :
544 18260 : if (newDestination) {
545 : // update arrival parameters
546 601 : SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
547 601 : *newParameter = veh.getParameter();
548 601 : newParameter->arrivalPosProcedure = ArrivalPosDefinition::GIVEN;
549 601 : newParameter->arrivalPos = newParkingArea->getEndLanePosition();
550 601 : veh.replaceParameter(newParameter);
551 : }
552 :
553 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
554 12195 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->getClosed())
555 36520 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->getClosed());
556 18260 : const double routeCost = router.recomputeCosts(newRoute, &veh, MSNet::getInstance()->getCurrentTimeStep());
557 18260 : ConstMSEdgeVector prevEdges(veh.getCurrentRouteEdge(), veh.getRoute().end());
558 18260 : const double previousCost = router.recomputeCosts(prevEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
559 18260 : const double savings = previousCost - routeCost;
560 18260 : resetClosedEdges(hasReroutingDevice, veh);
561 : //if (getID() == "ego") std::cout << SIMTIME << " pCost=" << previousCost << " cost=" << routeCost
562 : // << " prevEdges=" << toString(prevEdges)
563 : // << " newEdges=" << toString(edges)
564 : // << "\n";
565 :
566 : std::string errorMsg;
567 18260 : if (veh.replaceParkingArea(newParkingArea, errorMsg)) {
568 36520 : veh.replaceRouteEdges(newRoute, routeCost, savings, getID() + ":" + toString(SUMO_TAG_PARKING_AREA_REROUTE), false, false, false);
569 : } else {
570 0 : WRITE_WARNING("Vehicle '" + veh.getID() + "' at rerouter '" + getID()
571 : + "' could not reroute to new parkingArea '" + newParkingArea->getID()
572 : + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
573 : }
574 18260 : }
575 : return false;
576 91591 : }
577 528576 : if (rerouteDef->overtakeLocations.size() > 0) {
578 144 : if (!tObject.isVehicle()) {
579 : return false;
580 : }
581 : SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
582 144 : const ConstMSEdgeVector& oldEdges = veh.getRoute().getEdges();
583 : double bestSavings = -std::numeric_limits<double>::max();
584 : double netSaving;
585 : int bestIndex = -1;
586 : MSRouteIterator bestMainStart = oldEdges.end();
587 : std::pair<const SUMOVehicle*, MSRailSignal*> best_overtaker_signal(nullptr, nullptr);
588 : int index = -1;
589 : // sort locations by descending distance to vehicle
590 : std::vector<std::pair<int, int> > sortedLocs;
591 330 : for (const OvertakeLocation& oloc : rerouteDef->overtakeLocations) {
592 186 : index++;
593 186 : if (veh.getLength() > oloc.sidingLength) {
594 3 : continue;
595 : }
596 183 : auto mainStart = std::find(veh.getCurrentRouteEdge(), oldEdges.end(), oloc.main.front());
597 183 : if (mainStart == oldEdges.end()
598 : // exit main within
599 366 : || ConstMSEdgeVector(mainStart, mainStart + oloc.main.size()) != oloc.cMain
600 : // stop in main
601 366 : || (veh.hasStops() && veh.getNextStop().edge < (mainStart + oloc.main.size()))) {
602 : //std::cout << SIMTIME << " veh=" << veh.getID() << " wrong route or stop\n";
603 0 : continue;
604 : }
605 : // negated iterator distance for descending order
606 183 : sortedLocs.push_back(std::make_pair(-(int)(mainStart - veh.getCurrentRouteEdge()), index));
607 : }
608 144 : std::sort(sortedLocs.begin(), sortedLocs.end());
609 327 : for (const auto& item : sortedLocs) {
610 183 : index = item.second;
611 183 : const OvertakeLocation& oloc = rerouteDef->overtakeLocations[index];
612 183 : auto mainStart = veh.getCurrentRouteEdge() - item.first; // subtracting negative difference
613 183 : std::pair<const SUMOVehicle*, MSRailSignal*> overtaker_signal = overtakingTrain(veh, mainStart, oloc, netSaving);
614 183 : if (overtaker_signal.first != nullptr && netSaving > bestSavings) {
615 : bestSavings = netSaving;
616 : bestIndex = index;
617 : best_overtaker_signal = overtaker_signal;
618 : bestMainStart = mainStart;
619 : #ifdef DEBUG_OVERTAKING
620 : std::cout << " newBest index=" << bestIndex << " saving=" << bestSavings << "\n";
621 : #endif
622 : }
623 : }
624 144 : if (bestIndex >= 0) {
625 41 : const OvertakeLocation& oloc = rerouteDef->overtakeLocations[bestIndex];
626 41 : if (oloc.defer) {
627 5 : return false;
628 : }
629 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = hasReroutingDevice
630 0 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), rerouteDef->getClosed())
631 72 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), rerouteDef->getClosed());
632 36 : ConstMSEdgeVector newEdges(veh.getCurrentRouteEdge(), bestMainStart);
633 36 : newEdges.insert(newEdges.end(), oloc.siding.begin(), oloc.siding.end());
634 36 : newEdges.insert(newEdges.end(), bestMainStart + oloc.main.size(), oldEdges.end());
635 36 : const double routeCost = router.recomputeCosts(newEdges, &veh, MSNet::getInstance()->getCurrentTimeStep());
636 36 : const double savings = (router.recomputeCosts(oloc.cMain, &veh, MSNet::getInstance()->getCurrentTimeStep())
637 36 : - router.recomputeCosts(oloc.cSiding, &veh, MSNet::getInstance()->getCurrentTimeStep()));
638 72 : const std::string info = getID() + ":" + toString(SUMO_TAG_OVERTAKING_REROUTE) + ":" + best_overtaker_signal.first->getID();
639 36 : veh.replaceRouteEdges(newEdges, routeCost, savings, info, false, false, false);
640 36 : oloc.sidingExit->addConstraint(veh.getID(), new MSRailSignalConstraint_Predecessor(
641 36 : MSRailSignalConstraint::PREDECESSOR, best_overtaker_signal.second, best_overtaker_signal.first->getID(), 100, true));
642 36 : resetClosedEdges(hasReroutingDevice, veh);
643 36 : }
644 139 : return false;
645 144 : }
646 528432 : if (rerouteDef->stopAlternatives.size() > 0) {
647 : // somewhat similar to parkProbs but taking into account public transport schedule
648 12 : if (!tObject.isVehicle()) {
649 : return false;
650 : }
651 12 : checkStopSwitch(static_cast<MSBaseVehicle&>(tObject), rerouteDef);
652 : }
653 : // get rerouting params
654 528432 : ConstMSRoutePtr newRoute = rerouteDef->routeProbs.getOverallProb() > 0 ? rerouteDef->routeProbs.get() : nullptr;
655 : // we will use the route if given rather than calling our own dijsktra...
656 528432 : if (newRoute != nullptr) {
657 : #ifdef DEBUG_REROUTER
658 : if (DEBUGCOND(tObject)) {
659 : std::cout << " replacedRoute from routeDist " << newRoute->getID() << "\n";
660 : }
661 : #endif
662 522885 : tObject.replaceRoute(newRoute, getID());
663 522882 : return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
664 : }
665 : const MSEdge* newEdge = lastEdge;
666 : // ok, try using a new destination
667 : double newArrivalPos = -1;
668 5550 : const MSEdgeVector closedEdges = rerouteDef->getClosedEdges();
669 5550 : const bool destUnreachable = std::find(closedEdges.begin(), closedEdges.end(), lastEdge) != closedEdges.end();
670 : bool keepDestination = false;
671 : // if we have a closingReroute, only assign new destinations to vehicles which cannot reach their original destination
672 : // if we have a closingLaneReroute, no new destinations should be assigned
673 5550 : if (closedEdges.empty() || destUnreachable || rerouteDef->isVia) {
674 3823 : newEdge = rerouteDef->edgeProbs.getOverallProb() > 0 ? rerouteDef->edgeProbs.get() : lastEdge;
675 : assert(newEdge != nullptr);
676 3823 : if (newEdge == &mySpecialDest_terminateRoute) {
677 : keepDestination = true;
678 55 : newEdge = tObject.getEdge();
679 55 : newArrivalPos = tObject.getPositionOnLane(); // instant arrival
680 3768 : } else if (newEdge == &mySpecialDest_keepDestination || newEdge == lastEdge) {
681 1532 : if (destUnreachable && rerouteDef->permissionsAllowAll) {
682 : // if permissions aren't set vehicles will simply drive through
683 : // the closing unless terminated. If the permissions are specified, assume that the user wants
684 : // vehicles to stand and wait until the closing ends
685 63 : WRITE_WARNINGF(TL("Cannot keep destination edge '%' for vehicle '%' due to closed edges. Terminating route."), lastEdge->getID(), tObject.getID());
686 21 : newEdge = tObject.getEdge();
687 : } else {
688 : newEdge = lastEdge;
689 : }
690 : }
691 : }
692 : ConstMSEdgeVector edges;
693 : std::vector<MSTransportableRouter::TripItem> items;
694 : // we have a new destination, let's replace the route (if it is affected)
695 5550 : MSEdgeVector closed = rerouteDef->getClosedEdges();
696 5550 : Prohibitions prohibited = rerouteDef->getClosed();
697 7277 : if (rerouteDef->closed.empty() || destUnreachable || rerouteDef->isVia || affected(tObject.getUpcomingEdgeIDs(), closed)) {
698 5473 : if (tObject.isVehicle()) {
699 : SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
700 4003 : const bool canChangeDest = rerouteDef->edgeProbs.getOverallProb() > 0;
701 : MSVehicleRouter& router = hasReroutingDevice
702 4003 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), prohibited)
703 1693 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), prohibited);
704 4003 : bool ok = veh.reroute(now, getID(), router, false, false, canChangeDest, newEdge);
705 4000 : if (!ok && !keepDestination && canChangeDest) {
706 : // destination unreachable due to closed intermediate edges. pick among alternative targets
707 82 : RandomDistributor<MSEdge*> edgeProbs2 = rerouteDef->edgeProbs;
708 82 : edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
709 152 : while (!ok && edgeProbs2.getVals().size() > 0) {
710 110 : newEdge = edgeProbs2.get();
711 110 : edgeProbs2.remove(const_cast<MSEdge*>(newEdge));
712 110 : if (newEdge == &mySpecialDest_terminateRoute) {
713 42 : newEdge = veh.getEdge();
714 42 : newArrivalPos = veh.getPositionOnLane(); // instant arrival
715 : }
716 110 : if (newEdge == &mySpecialDest_keepDestination && !rerouteDef->permissionsAllowAll) {
717 : newEdge = lastEdge;
718 : break;
719 : }
720 70 : ok = veh.reroute(now, getID(), router, false, false, true, newEdge);
721 : }
722 :
723 : }
724 4000 : if (!rerouteDef->isVia) {
725 : #ifdef DEBUG_REROUTER
726 : if (DEBUGCOND(tObject)) std::cout << " rerouting: newDest=" << newEdge->getID()
727 : << " newEdges=" << toString(edges)
728 : << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
729 : << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->getClosedEdges()) << "\n";
730 : #endif
731 4000 : if (ok && newArrivalPos != -1) {
732 : // must be called here because replaceRouteEdges may also set the arrivalPos
733 86 : veh.setArrivalPos(newArrivalPos);
734 : }
735 :
736 : }
737 : } else {
738 : // person rerouting here
739 : MSTransportableRouter& router = hasReroutingDevice
740 1470 : ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), prohibited)
741 1470 : : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, prohibited);
742 4410 : const bool success = router.compute(tObject.getEdge(), newEdge, tObject.getPositionOnLane(), "",
743 1470 : rerouteDef->isVia ? newEdge->getLength() / 2. : tObject.getParameter().arrivalPos, "",
744 1470 : tObject.getMaxSpeed(), nullptr, tObject.getVTypeParameter(), 0, now, items);
745 1470 : if (!rerouteDef->isVia) {
746 700 : if (success) {
747 1400 : for (const MSTransportableRouter::TripItem& it : items) {
748 700 : if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
749 : edges.pop_back();
750 : }
751 700 : edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
752 700 : if (!edges.empty()) {
753 700 : static_cast<MSPerson&>(tObject).replaceWalk(edges, tObject.getPositionOnLane(), 0, 1);
754 : }
755 : }
756 : } else {
757 : // maybe the pedestrian model still finds a way (JuPedSim)
758 0 : static_cast<MSPerson&>(tObject).replaceWalk({tObject.getEdge(), newEdge}, tObject.getPositionOnLane(), 0, 1);
759 : }
760 : }
761 : }
762 5470 : if (!prohibited.empty()) {
763 1729 : resetClosedEdges(hasReroutingDevice, tObject);
764 : }
765 : }
766 : // it was only a via so calculate the remaining part
767 5547 : if (rerouteDef->isVia) {
768 770 : if (tObject.isVehicle()) {
769 : SUMOVehicle& veh = static_cast<SUMOVehicle&>(tObject);
770 0 : if (!edges.empty()) {
771 : edges.pop_back();
772 : }
773 : MSVehicleRouter& router = hasReroutingDevice
774 0 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass(), prohibited)
775 0 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), prohibited);
776 0 : router.compute(newEdge, lastEdge, &veh, now, edges);
777 0 : const double routeCost = router.recomputeCosts(edges, &veh, now);
778 : hasReroutingDevice
779 0 : ? MSRoutingEngine::getRouterTT(veh.getRNGIndex(), veh.getVClass())
780 0 : : MSNet::getInstance()->getRouterTT(veh.getRNGIndex()); // reset closed edges
781 0 : const bool useNewRoute = veh.replaceRouteEdges(edges, routeCost, 0, getID());
782 : #ifdef DEBUG_REROUTER
783 : if (DEBUGCOND(tObject)) std::cout << " rerouting: newDest=" << newEdge->getID()
784 : << " newEdges=" << toString(edges)
785 : << " useNewRoute=" << useNewRoute << " newArrivalPos=" << newArrivalPos << " numClosed=" << rerouteDef->closed.size()
786 : << " destUnreachable=" << destUnreachable << " containsClosed=" << veh.getRoute().containsAnyOf(rerouteDef->getClosedEdges()) << "\n";
787 : #endif
788 0 : if (useNewRoute && newArrivalPos != -1) {
789 : // must be called here because replaceRouteEdges may also set the arrivalPos
790 0 : veh.setArrivalPos(newArrivalPos);
791 : }
792 : } else {
793 : // person rerouting here
794 770 : bool success = !items.empty();
795 770 : if (success) {
796 : MSTransportableRouter& router = hasReroutingDevice
797 770 : ? MSRoutingEngine::getIntermodalRouterTT(tObject.getRNGIndex(), prohibited)
798 770 : : MSNet::getInstance()->getIntermodalRouter(tObject.getRNGIndex(), 0, prohibited);
799 2310 : success = router.compute(newEdge, lastEdge, newEdge->getLength() / 2., "",
800 770 : tObject.getParameter().arrivalPos, "",
801 770 : tObject.getMaxSpeed(), nullptr, tObject.getVTypeParameter(), 0, now, items);
802 : }
803 770 : if (success) {
804 2310 : for (const MSTransportableRouter::TripItem& it : items) {
805 1540 : if (!it.edges.empty() && !edges.empty() && edges.back() == it.edges.front()) {
806 : edges.pop_back();
807 : }
808 1540 : edges.insert(edges.end(), std::make_move_iterator(it.edges.begin()), std::make_move_iterator(it.edges.end()));
809 : }
810 770 : if (!edges.empty()) {
811 770 : static_cast<MSPerson&>(tObject).replaceWalk(edges, tObject.getPositionOnLane(), 0, 1);
812 : }
813 : } else {
814 : // maybe the pedestrian model still finds a way (JuPedSim)
815 3 : static_cast<MSPerson&>(tObject).replaceWalk({tObject.getEdge(), newEdge, lastEdge}, tObject.getPositionOnLane(), 0, 1);
816 : }
817 : }
818 770 : if (!prohibited.empty()) {
819 0 : resetClosedEdges(hasReroutingDevice, tObject);
820 : }
821 : }
822 : return false; // XXX another interval could appear later but we would have to track whether the currenty interval was already used
823 5559 : }
824 :
825 :
826 : void
827 1 : MSTriggeredRerouter::setUserMode(bool val) {
828 1 : myAmInUserMode = val;
829 1 : }
830 :
831 :
832 : void
833 1 : MSTriggeredRerouter::setUserUsageProbability(double prob) {
834 1 : myUserProbability = prob;
835 1 : }
836 :
837 :
838 : bool
839 0 : MSTriggeredRerouter::inUserMode() const {
840 0 : return myAmInUserMode;
841 : }
842 :
843 :
844 : double
845 5644 : MSTriggeredRerouter::getProbability() const {
846 5644 : return myAmInUserMode ? myUserProbability : myProbability;
847 : }
848 :
849 :
850 : double
851 0 : MSTriggeredRerouter::getUserProbability() const {
852 0 : return myUserProbability;
853 : }
854 :
855 :
856 : double
857 101736 : MSTriggeredRerouter::getStoppingPlaceOccupancy(MSStoppingPlace* sp) {
858 101736 : return (double)(sp->getElement() == SUMO_TAG_PARKING_AREA
859 101678 : ? dynamic_cast<MSParkingArea*>(sp)->getOccupancy()
860 58 : : sp->getStoppedVehicles().size());
861 : }
862 :
863 :
864 : double
865 81871 : MSTriggeredRerouter::getLastStepStoppingPlaceOccupancy(MSStoppingPlace* sp) {
866 81871 : return (double)(sp->getElement() == SUMO_TAG_PARKING_AREA
867 81835 : ? dynamic_cast<MSParkingArea*>(sp)->getLastStepOccupancy()
868 36 : : sp->getStoppedVehicles().size());
869 : }
870 :
871 :
872 : double
873 259094 : MSTriggeredRerouter::getStoppingPlaceCapacity(MSStoppingPlace* sp) {
874 : if (myBlockedStoppingPlaces.count(sp) == 0) {
875 : return (double)(sp->getElement() == SUMO_TAG_PARKING_AREA
876 259078 : ? dynamic_cast<MSParkingArea*>(sp)->getCapacity()
877 : // assume only one vehicle at a time (for stationReroute)
878 : : 1.);
879 : } else {
880 : return 0.;
881 : }
882 : }
883 :
884 :
885 : void
886 54344 : MSTriggeredRerouter::rememberBlockedStoppingPlace(SUMOVehicle& veh, const MSStoppingPlace* parkingArea, bool blocked) {
887 54344 : veh.rememberBlockedParkingArea(parkingArea, blocked);
888 54344 : }
889 :
890 :
891 : void
892 86339 : MSTriggeredRerouter::rememberStoppingPlaceScore(SUMOVehicle& veh, MSStoppingPlace* parkingArea, const std::string& score) {
893 86339 : veh.rememberParkingAreaScore(parkingArea, score);
894 86339 : }
895 :
896 :
897 : void
898 19077 : MSTriggeredRerouter::resetStoppingPlaceScores(SUMOVehicle& veh) {
899 19077 : veh.resetParkingAreaScores();
900 19077 : }
901 :
902 :
903 : SUMOTime
904 51792 : MSTriggeredRerouter::sawBlockedStoppingPlace(SUMOVehicle& veh, MSStoppingPlace* parkingArea, bool local) {
905 51792 : return veh.sawBlockedParkingArea(parkingArea, local);
906 : }
907 :
908 :
909 : int
910 58330 : MSTriggeredRerouter::getNumberStoppingPlaceReroutes(SUMOVehicle& veh) {
911 58330 : return veh.getNumberParkingReroutes();
912 : }
913 :
914 :
915 : void
916 19077 : MSTriggeredRerouter::setNumberStoppingPlaceReroutes(SUMOVehicle& veh, int value) {
917 19077 : veh.setNumberParkingReroutes(value);
918 19077 : }
919 :
920 :
921 : MSParkingArea*
922 91591 : MSTriggeredRerouter::rerouteParkingArea(const MSTriggeredRerouter::RerouteInterval* rerouteDef,
923 : SUMOVehicle& veh, bool& newDestination, ConstMSEdgeVector& newRoute) {
924 91591 : MSStoppingPlace* destStoppingPlace = veh.getNextParkingArea();
925 91591 : if (destStoppingPlace == nullptr) {
926 : // not driving towards the right type of stop
927 : return nullptr;
928 : }
929 : std::vector<StoppingPlaceVisible> parks;
930 255067 : for (auto cand : rerouteDef->parkProbs.getVals()) {
931 173140 : if (cand.first->accepts(&veh)) {
932 172460 : parks.push_back(cand);
933 : }
934 : }
935 : StoppingPlaceParamMap_t addInput = {};
936 163854 : return dynamic_cast<MSParkingArea*>(rerouteStoppingPlace(destStoppingPlace, parks, rerouteDef->parkProbs.getProbs(), veh, newDestination, newRoute, addInput, rerouteDef->getClosed()));
937 81927 : }
938 :
939 :
940 : std::pair<const SUMOVehicle*, MSRailSignal*>
941 183 : MSTriggeredRerouter::overtakingTrain(const SUMOVehicle& veh,
942 : ConstMSEdgeVector::const_iterator mainStart,
943 : const OvertakeLocation& oloc,
944 : double& netSaving) {
945 183 : const ConstMSEdgeVector& route = veh.getRoute().getEdges();
946 : const MSEdgeVector& main = oloc.main;
947 183 : const double vMax = veh.getMaxSpeed();
948 366 : const double prio = veh.getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".prio", false, DEFAULT_PRIO_OVERTAKEN, false);
949 183 : MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
950 437 : for (MSVehicleControl::constVehIt it_veh = c.loadedVehBegin(); it_veh != c.loadedVehEnd(); ++it_veh) {
951 307 : const MSBaseVehicle* veh2 = dynamic_cast<const MSBaseVehicle*>((*it_veh).second);
952 307 : if (veh2->isOnRoad() && veh2->getMaxSpeed() > vMax) {
953 93 : const double arrivalDelay = veh2->getStopArrivalDelay();
954 182 : const double delay = MAX2(veh2->getStopDelay(), arrivalDelay == INVALID_DOUBLE ? 0 : arrivalDelay);
955 279 : if (delay > veh2->getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".maxDelay", false, DEFAULT_MAXDELAY, false)) {
956 : continue;
957 : }
958 89 : const ConstMSEdgeVector& route2 = veh2->getRoute().getEdges();
959 : auto itOnMain2 = route2.end();
960 : int mainIndex = 0;
961 110 : for (const MSEdge* m : main) {
962 105 : itOnMain2 = std::find(veh2->getCurrentRouteEdge(), route2.end(), m);
963 105 : if (itOnMain2 != route2.end()) {
964 : break;
965 : }
966 21 : mainIndex++;
967 : }
968 89 : if (itOnMain2 != route2.end() && itOnMain2 > veh2->getCurrentRouteEdge()) {
969 : auto itOnMain = mainStart + mainIndex;
970 : double timeToMain = 0;
971 371 : for (auto it = veh.getCurrentRouteEdge(); it != itOnMain; it++) {
972 290 : timeToMain += (*it)->getMinimumTravelTime(&veh);
973 : }
974 : // veh2 may be anywhere on the current edge so we have to discount
975 81 : double timeToMain2 = -veh2->getEdge()->getMinimumTravelTime(veh2) * veh2->getPositionOnLane() / veh2->getEdge()->getLength();
976 : double timeToLastSignal2 = timeToMain2;
977 562 : for (auto it = veh2->getCurrentRouteEdge(); it != itOnMain2; it++) {
978 481 : timeToMain2 += (*it)->getMinimumTravelTime(veh2);
979 481 : auto signal = getRailSignal(*it);
980 481 : if (signal) {
981 : timeToLastSignal2 = timeToMain2;
982 : #ifdef DEBUG_OVERTAKING
983 : std::cout << " lastBeforeMain2 " << signal->getID() << "\n";
984 : #endif
985 : }
986 : }
987 : double exitMainTime = timeToMain;
988 : double exitMainBlockTime2 = timeToMain2;
989 : double commonTime = 0;
990 : double commonTime2 = 0;
991 : int nCommon = 0;
992 : auto exitMain2 = itOnMain2;
993 : const MSRailSignal* firstAfterMain = nullptr;
994 : const MSEdge* common = nullptr;
995 81 : double vMinCommon = (*itOnMain)->getVehicleMaxSpeed(&veh);
996 81 : double vMinCommon2 = (*itOnMain2)->getVehicleMaxSpeed(veh2);
997 : while (itOnMain2 != route2.end()
998 794 : && itOnMain != route.end()
999 1657 : && *itOnMain == *itOnMain2) {
1000 : common = *itOnMain;
1001 785 : commonTime += common->getMinimumTravelTime(&veh);
1002 785 : commonTime2 += common->getMinimumTravelTime(veh2);
1003 785 : vMinCommon = MIN2(vMinCommon, common->getVehicleMaxSpeed(&veh));
1004 785 : vMinCommon2 = MIN2(vMinCommon2, common->getVehicleMaxSpeed(veh2));
1005 785 : const bool onMain = nCommon < (int)main.size() - mainIndex;
1006 785 : if (onMain) {
1007 240 : exitMainTime = timeToMain + commonTime;
1008 : }
1009 785 : if (firstAfterMain == nullptr) {
1010 480 : exitMainBlockTime2 = timeToMain2 + commonTime2;
1011 : }
1012 785 : auto signal = getRailSignal(common);
1013 785 : if (signal) {
1014 318 : if (!onMain && firstAfterMain == nullptr) {
1015 : firstAfterMain = signal;
1016 : #ifdef DEBUG_OVERTAKING
1017 : std::cout << " firstAfterMain " << signal->getID() << "\n";
1018 : #endif
1019 : }
1020 : }
1021 785 : nCommon++;
1022 : itOnMain++;
1023 : itOnMain2++;
1024 : }
1025 81 : const double vMaxLast = common->getVehicleMaxSpeed(&veh);
1026 81 : const double vMaxLast2 = common->getVehicleMaxSpeed(veh2);
1027 81 : commonTime += veh.getLength() / vMaxLast;
1028 81 : exitMainBlockTime2 += veh2->getLength() / vMaxLast2;
1029 81 : exitMain2 += MIN2(nCommon, (int)main.size() - mainIndex);
1030 81 : double timeLoss2 = MAX2(0.0, timeToMain + veh.getLength() / oloc.siding.front()->getVehicleMaxSpeed(&veh) - timeToLastSignal2);
1031 81 : const double saving = timeToMain + commonTime - (timeToMain2 + commonTime2) - timeLoss2;
1032 81 : const double loss = exitMainBlockTime2 - exitMainTime;
1033 162 : const double prio2 = veh2->getFloatParam(toString(SUMO_TAG_OVERTAKING_REROUTE) + ".prio", false, DEFAULT_PRIO_OVERTAKER, false);
1034 : // losses from acceleration after stopping at a signal
1035 81 : const double accelTimeLoss = loss > 0 ? 0.5 * vMinCommon / veh.getVehicleType().getCarFollowModel().getMaxAccel() : 0;
1036 81 : const double accelTimeLoss2 = timeLoss2 > 0 ? 0.5 * vMinCommon2 / veh2->getVehicleType().getCarFollowModel().getMaxAccel() : 0;
1037 81 : netSaving = prio2 * (saving - accelTimeLoss2) - prio * (loss + accelTimeLoss);
1038 : #ifdef DEBUG_OVERTAKING
1039 : std::cout << SIMTIME << " veh=" << veh.getID() << " veh2=" << veh2->getID()
1040 : << " sidingStart=" << oloc.siding.front()->getID()
1041 : << " ttm=" << timeToMain << " ttm2=" << timeToMain2
1042 : << " nCommon=" << nCommon << " cT=" << commonTime << " cT2=" << commonTime2
1043 : << " em=" << exitMainTime << " emb2=" << exitMainBlockTime2
1044 : << " ttls2=" << timeToLastSignal2
1045 : << " saving=" << saving << " loss=" << loss
1046 : << " atl=" << accelTimeLoss << " atl2=" << accelTimeLoss2 << " tl2=" << timeLoss2
1047 : << " prio=" << prio << " prio2=" << prio2 << " netSaving=" << netSaving << "\n";
1048 : #endif
1049 81 : if (netSaving > oloc.minSaving) {
1050 53 : MSRailSignal* s = findSignal(veh2->getCurrentRouteEdge(), exitMain2);
1051 53 : if (s != nullptr) {
1052 53 : return std::make_pair(veh2, s);
1053 : }
1054 : }
1055 : }
1056 : }
1057 : }
1058 130 : return std::make_pair(nullptr, nullptr);
1059 : }
1060 :
1061 :
1062 : void
1063 12 : MSTriggeredRerouter::checkStopSwitch(MSBaseVehicle& ego, const MSTriggeredRerouter::RerouteInterval* def) {
1064 : myBlockedStoppingPlaces.clear();
1065 : #ifdef DEBUG_REROUTER
1066 : std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << "\n";
1067 : #endif
1068 12 : if (!ego.hasStops()) {
1069 0 : return;
1070 : }
1071 12 : const MSStop& stop = ego.getNextStop();
1072 12 : if (stop.reached || stop.joinTriggered || (stop.pars.arrival < 0 && stop.pars.until < 0)) {
1073 : return;
1074 : }
1075 12 : MSStoppingPlace* cur = nullptr;
1076 24 : for (MSStoppingPlace* sp : stop.getPlaces()) {
1077 12 : for (auto item : def->stopAlternatives) {
1078 12 : if (sp == item.first) {
1079 12 : cur = sp;
1080 12 : break;
1081 : }
1082 : }
1083 12 : }
1084 12 : if (cur == nullptr) {
1085 : return;
1086 : }
1087 12 : std::vector<const SUMOVehicle*> stopped = cur->getStoppedVehicles();
1088 : #ifdef DEBUG_REROUTER
1089 : std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopped=" << toString(stopped) << "\n";
1090 : #endif
1091 : SUMOTime stoppedDuration = -1;
1092 12 : if (stopped.empty()) {
1093 : /// look upstream for vehicles that stop on this lane before ego arrives
1094 8 : const MSLane& stopLane = cur->getLane();
1095 8 : MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
1096 25 : for (MSVehicleControl::constVehIt it_veh = c.loadedVehBegin(); it_veh != c.loadedVehEnd(); ++it_veh) {
1097 17 : const MSBaseVehicle* veh = dynamic_cast<const MSBaseVehicle*>((*it_veh).second);
1098 17 : if (veh->isOnRoad() && veh->hasStops()) {
1099 17 : const MSStop& vehStop = veh->getNextStop();
1100 17 : if (vehStop.pars.lane == stopLane.getID()) {
1101 : myBlockedStoppingPlaces.insert(cur);
1102 10 : if (veh->isStopped()) {
1103 : // stopped somewhere else on the same lane
1104 2 : stoppedDuration = MAX3((SUMOTime)0, stoppedDuration, veh->getStopDuration());
1105 : } else {
1106 8 : std::pair<double, double> timeDist = veh->estimateTimeToNextStop();
1107 8 : SUMOTime timeTo = TIME2STEPS(timeDist.first);
1108 8 : stoppedDuration = MAX3((SUMOTime)0, stoppedDuration, timeTo + vehStop.getMinDuration(SIMSTEP + timeTo));
1109 : }
1110 : }
1111 : }
1112 : }
1113 : } else {
1114 : stoppedDuration = 0;
1115 8 : for (const SUMOVehicle* veh : cur->getStoppedVehicles()) {
1116 4 : stoppedDuration = MAX2(stoppedDuration, veh->getStopDuration());
1117 4 : }
1118 : }
1119 12 : if (stoppedDuration < 0) {
1120 : return;
1121 : }
1122 : /// @todo: consider time for conflict veh to leave the block
1123 12 : const SUMOTime stopFree = SIMSTEP + stoppedDuration;
1124 12 : const SUMOTime scheduledArrival = stop.pars.arrival >= 0 ? stop.pars.arrival : stop.pars.until - stop.pars.duration;
1125 : #ifdef DEBUG_REROUTER
1126 : std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopFree=" << stopFree << " scheduledArrival=" << time2string(scheduledArrival) << "\n";
1127 : #endif
1128 12 : if (stopFree < scheduledArrival) {
1129 : // no conflict according to the schedule
1130 : return;
1131 : }
1132 12 : const SUMOTime estimatedArrival = SIMSTEP + (stop.pars.arrival >= 0
1133 12 : ? TIME2STEPS(ego.getStopArrivalDelay())
1134 16 : : TIME2STEPS(ego.getStopDelay()) - stop.pars.duration);
1135 : #ifdef DEBUG_REROUTER
1136 : std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " stopFree=" << stopFree << " estimatedArrival=" << time2string(estimatedArrival) << "\n";
1137 : #endif
1138 12 : if (stopFree < estimatedArrival) {
1139 : // no conflict when considering current delay
1140 : return;
1141 : }
1142 12 : const std::vector<double> probs(def->stopAlternatives.size(), 1.);
1143 : StoppingPlaceParamMap_t scores = {};
1144 : bool newDestination;
1145 : ConstMSEdgeVector newRoute;
1146 : // @todo: consider future conflicts caused by rerouting
1147 : // @todo: reject alternatives with large detour
1148 12 : const MSStoppingPlace* alternative = rerouteStoppingPlace(nullptr, def->stopAlternatives, probs, ego, newDestination, newRoute, scores);
1149 : #ifdef DEBUG_REROUTER
1150 : std::cout << SIMTIME << " " << getID() << " ego=" << ego.getID() << " alternative=" << Named::getIDSecure(alternative) << "\n";
1151 : #endif
1152 12 : if (alternative != nullptr) {
1153 : // @todo adapt plans of any riders
1154 : //for (MSTransportable* p : ego.getPersons()) {
1155 : // p->rerouteParkingArea(ego.getNextParkingArea(), newParkingArea);
1156 : //}
1157 :
1158 12 : if (newDestination) {
1159 : // update arrival parameters
1160 0 : SUMOVehicleParameter* newParameter = new SUMOVehicleParameter();
1161 0 : *newParameter = ego.getParameter();
1162 0 : newParameter->arrivalPosProcedure = ArrivalPosDefinition::GIVEN;
1163 0 : newParameter->arrivalPos = alternative->getEndLanePosition();
1164 0 : ego.replaceParameter(newParameter);
1165 : }
1166 :
1167 12 : SUMOVehicleParameter::Stop newStop = stop.pars;
1168 12 : newStop.lane = alternative->getLane().getID();
1169 12 : newStop.startPos = alternative->getBeginLanePosition();
1170 12 : newStop.endPos = alternative->getEndLanePosition();
1171 12 : switch (alternative->getElement()) {
1172 0 : case SUMO_TAG_PARKING_AREA:
1173 : newStop.parkingarea = alternative->getID();
1174 : break;
1175 0 : case SUMO_TAG_CONTAINER_STOP:
1176 : newStop.containerstop = alternative->getID();
1177 : break;
1178 0 : case SUMO_TAG_CHARGING_STATION:
1179 : newStop.chargingStation = alternative->getID();
1180 : break;
1181 0 : case SUMO_TAG_OVERHEAD_WIRE_SEGMENT:
1182 : newStop.overheadWireSegment = alternative->getID();
1183 : break;
1184 12 : case SUMO_TAG_BUS_STOP:
1185 : case SUMO_TAG_TRAIN_STOP:
1186 : default:
1187 : newStop.busstop = alternative->getID();
1188 : }
1189 : std::string errorMsg;
1190 24 : if (!ego.replaceStop(0, newStop, getID() + ":" + toString(SUMO_TAG_STATION_REROUTE), false, errorMsg)) {
1191 0 : WRITE_WARNING("Vehicle '" + ego.getID() + "' at rerouter '" + getID()
1192 : + "' could not perform stationReroute to '" + alternative->getID()
1193 : + "' reason=" + errorMsg + ", time=" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + ".");
1194 : }
1195 12 : }
1196 24 : }
1197 :
1198 :
1199 : MSRailSignal*
1200 152 : MSTriggeredRerouter::findSignal(ConstMSEdgeVector::const_iterator begin, ConstMSEdgeVector::const_iterator end) {
1201 152 : auto it = end;
1202 : do {
1203 : it--;
1204 304 : auto signal = getRailSignal(*it);
1205 304 : if (signal != nullptr) {
1206 152 : return signal;
1207 : }
1208 152 : } while (it != begin);
1209 : return nullptr;
1210 : }
1211 :
1212 :
1213 : MSRailSignal*
1214 1570 : MSTriggeredRerouter::getRailSignal(const MSEdge* edge) {
1215 1570 : if (edge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
1216 732 : for (const MSLink* link : edge->getLanes().front()->getLinkCont()) {
1217 732 : if (link->getTLLogic() != nullptr) {
1218 732 : return dynamic_cast<MSRailSignal*>(const_cast<MSTrafficLightLogic*>(link->getTLLogic()));
1219 : }
1220 : }
1221 : }
1222 : return nullptr;
1223 : }
1224 :
1225 : bool
1226 1176563 : MSTriggeredRerouter::applies(const SUMOTrafficObject& obj) const {
1227 1176563 : if (myVehicleTypes.empty() || myVehicleTypes.count(obj.getVehicleType().getOriginalID()) > 0) {
1228 1176493 : return true;
1229 : } else {
1230 140 : std::set<std::string> vTypeDists = MSNet::getInstance()->getVehicleControl().getVTypeDistributionMembership(obj.getVehicleType().getOriginalID());
1231 70 : for (auto vTypeDist : vTypeDists) {
1232 : if (myVehicleTypes.count(vTypeDist) > 0) {
1233 : return true;
1234 : }
1235 : }
1236 70 : return false;
1237 : }
1238 : }
1239 :
1240 :
1241 : bool
1242 123608 : MSTriggeredRerouter::affected(const std::set<SUMOTrafficObject::NumericalID>& edgeIndices, const MSEdgeVector& closed) {
1243 141040 : for (const MSEdge* const e : closed) {
1244 66140 : if (edgeIndices.count(e->getNumericalID()) > 0) {
1245 : return true;
1246 : }
1247 : }
1248 : return false;
1249 : }
1250 :
1251 :
1252 : void
1253 23532 : MSTriggeredRerouter::checkParkingRerouteConsistency() {
1254 : // if a parkingArea is a rerouting target, it should generally have a
1255 : // rerouter on its edge or vehicles will be stuck there once it's full.
1256 : // The user should receive a Warning in this case
1257 : std::set<MSEdge*> parkingRerouterEdges;
1258 : std::map<MSParkingArea*, std::string, ComparatorIdLess> targetedParkingArea; // paID -> targetingRerouter
1259 27517 : for (const auto& rr : myInstances) {
1260 : bool hasParkingReroute = false;
1261 7763 : for (const RerouteInterval& interval : rr.second->myIntervals) {
1262 3778 : if (interval.parkProbs.getOverallProb() > 0) {
1263 : hasParkingReroute = true;
1264 15735 : for (const StoppingPlaceVisible& pav : interval.parkProbs.getVals()) {
1265 27030 : targetedParkingArea[dynamic_cast<MSParkingArea*>(pav.first)] = rr.first;
1266 : }
1267 : }
1268 : }
1269 3985 : if (hasParkingReroute) {
1270 2220 : parkingRerouterEdges.insert(rr.second->myEdges.begin(), rr.second->myEdges.end());
1271 : }
1272 : }
1273 26361 : for (const auto& item : targetedParkingArea) {
1274 2829 : if (parkingRerouterEdges.count(&item.first->getLane().getEdge()) == 0) {
1275 1168 : WRITE_WARNINGF(TL("ParkingArea '%' is targeted by rerouter '%' but doesn't have its own rerouter. This may cause parking search to abort."),
1276 : item.first->getID(), item.second);
1277 : }
1278 : }
1279 23532 : }
1280 :
1281 :
1282 : void
1283 20025 : MSTriggeredRerouter::resetClosedEdges(bool hasReroutingDevice, const SUMOTrafficObject& o) {
1284 : // getRouterTT without prohibitions removes previous prohibitions
1285 20025 : if (o.isVehicle()) {
1286 : hasReroutingDevice
1287 40050 : ? MSRoutingEngine::getRouterTT(o.getRNGIndex(), o.getVClass())
1288 27573 : : MSNet::getInstance()->getRouterTT(o.getRNGIndex());
1289 : } else {
1290 : hasReroutingDevice
1291 0 : ? MSRoutingEngine::getIntermodalRouterTT(o.getRNGIndex())
1292 0 : : MSNet::getInstance()->getIntermodalRouter(o.getRNGIndex(), 0);
1293 : }
1294 20025 : }
1295 :
1296 : /****************************************************************************/
|