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 MSStoppingPlaceRerouter.cpp
15 : /// @author Mirko Barthauer
16 : /// @date Mon, 17 June 2024
17 : ///
18 : // The StoppingPlaceRerouter provides an interface to structure the rerouting
19 : // to the best StoppingPlace according to the evaluation components and
20 : // associated weights.
21 : /****************************************************************************/
22 : #include <utils/vehicle/SUMOVehicle.h>
23 : #include <microsim/MSEdge.h>
24 : #include <microsim/MSGlobals.h>
25 : #include <microsim/MSLane.h>
26 : #include <microsim/MSRoute.h>
27 : #include <microsim/MSParkingArea.h>
28 : #include <microsim/MSStoppingPlace.h>
29 : #include <microsim/MSVehicleType.h>
30 : #include <microsim/trigger/MSChargingStation.h>
31 : #include "MSStoppingPlaceRerouter.h"
32 :
33 : //#define DEBUG_STOPPINGPLACE
34 : #define DEBUGCOND (veh.isSelected())
35 : //#define DEBUGCOND (true)
36 :
37 :
38 : ///@brief Constructor
39 4113 : MSStoppingPlaceRerouter::MSStoppingPlaceRerouter(std::string paramPrefix, bool checkValidity, StoppingPlaceParamMap_t addEvalParams, StoppingPlaceParamSwitchMap_t addInvertParams) :
40 4113 : myParamPrefix(paramPrefix), myCheckValidity(checkValidity) {
41 37017 : myEvalParams = { {"probability", 0.}, {"capacity", 0.}, {"timefrom", 0.}, {"timeto", 0.}, {"distancefrom", 0.}, {"distanceto", 1.}, {"absfreespace", 0.}, {"relfreespace", 0.}, };
42 37017 : myInvertParams = { {"probability", false}, { "capacity", true }, { "timefrom", false }, { "timeto", false }, { "distancefrom", false }, { "distanceto", false }, { "absfreespace", true }, { "relfreespace", true } };
43 4331 : for (auto param : addEvalParams) {
44 218 : myEvalParams[param.first] = param.second;
45 436 : myInvertParams[param.first] = (addInvertParams.count(param.first) > 0) ? addInvertParams[param.first] : false;
46 : }
47 37235 : for (auto param : myEvalParams) {
48 33122 : myNormParams.insert({param.first, param.first != "probability"});
49 : }
50 4331 : }
51 :
52 : MSStoppingPlace*
53 93984 : MSStoppingPlaceRerouter::rerouteStoppingPlace(MSStoppingPlace* destStoppingPlace, const std::vector<StoppingPlaceVisible>& stoppingPlaceCandidates, const std::vector<double>& probs, SUMOVehicle& veh, bool& newDestination, ConstMSEdgeVector& newRoute, StoppingPlaceParamMap_t& scores,
54 : const Prohibitions& closedEdges, const int insertStopIndex, const bool keepCurrentStop) {
55 : // Reroute destination from initial stopping place to an alternative stopping place
56 : // if the following conditions are met:
57 : // - next stop target is a stopping place of the right type
58 : // - target is included in the current alternative set
59 : // - target is visibly full
60 : // Any stopping places that are visibly full at the current location are
61 : // committed to the stopping place memory corresponding to their type
62 :
63 93984 : MSStoppingPlace* nearStoppingPlace = nullptr;
64 :
65 : // get vehicle params
66 : bool destVisible = false;
67 93984 : if (destStoppingPlace != nullptr) {
68 93845 : destVisible = (&destStoppingPlace->getLane().getEdge() == veh.getEdge());
69 : // if the vehicle is on the destination stop edge it is always visible
70 209951 : for (auto stoppingPlace : stoppingPlaceCandidates) {
71 141568 : if (stoppingPlace.first == destStoppingPlace && stoppingPlace.second) {
72 : destVisible = true;
73 : break;
74 : }
75 : }
76 : }
77 93984 : const MSRoute& route = veh.getRoute();
78 :
79 93984 : MSStoppingPlace* onTheWay = nullptr;
80 93984 : const int stopAnywhere = (int)getWeight(veh, "anywhere", -1);
81 93984 : const bool ignoreDest = getWeight(veh, "ignoreDest", destStoppingPlace != nullptr ? 0 : 1) != 0;
82 : // check whether we are ready to accept any free stopping place along the
83 : // way to our destination
84 93984 : if (stopAnywhere < 0 || stopAnywhere > getNumberStoppingPlaceReroutes(veh)) {
85 93949 : if (!destVisible) {
86 : // cannot determine destination occupancy, only register visibly full
87 121043 : for (const StoppingPlaceVisible& stoppingPlace : stoppingPlaceCandidates) {
88 70912 : if (stoppingPlace.second && getLastStepStoppingPlaceOccupancy(stoppingPlace.first, &veh) >= getStoppingPlaceCapacity(stoppingPlace.first)) {
89 5901 : rememberStoppingPlaceScore(veh, stoppingPlace.first, "occupied");
90 5901 : rememberBlockedStoppingPlace(veh, stoppingPlace.first, &stoppingPlace.first->getLane().getEdge() == veh.getEdge());
91 : }
92 : }
93 : #ifdef DEBUG_STOPPINGPLACE
94 : if (DEBUGCOND) {
95 : //std::cout << SIMTIME << " veh=" << veh.getID() << " dest=" << ((destStoppingPlace == nullptr)? "null" : destStoppingPlace->getID()) << " stopAnywhere=" << stopAnywhere << " reroutes=" << getNumberStoppingPlaceReroutes(veh) << " stay on original route\n";
96 : }
97 : #endif
98 : }
99 : } else {
100 : double bestDist = std::numeric_limits<double>::max();
101 35 : const double brakeGap = veh.getBrakeGap(true);
102 200 : for (const StoppingPlaceVisible& item : stoppingPlaceCandidates) {
103 165 : if (item.second) {
104 70 : if (&item.first->getLane().getEdge() == veh.getEdge()
105 70 : && getLastStepStoppingPlaceOccupancy(item.first, &veh) < getStoppingPlaceCapacity(item.first)) {
106 25 : const double distToStart = item.first->getBeginLanePosition() - veh.getPositionOnLane();
107 25 : const double distToEnd = item.first->getEndLanePosition() - veh.getPositionOnLane();
108 25 : if (distToEnd > brakeGap) {
109 40 : rememberStoppingPlaceScore(veh, item.first, "dist=" + toString(distToStart));
110 20 : if (distToStart < bestDist) {
111 : bestDist = distToStart;
112 20 : onTheWay = item.first;
113 : }
114 : } else {
115 10 : rememberStoppingPlaceScore(veh, item.first, "tooClose");
116 : }
117 : }
118 : }
119 : }
120 : #ifdef DEBUG_STOPPINGPLACE
121 : if (DEBUGCOND) {
122 : std::cout << SIMTIME << " veh=" << veh.getID()
123 : << " dest=" << ((destStoppingPlace == nullptr) ? "null" : destStoppingPlace->getID()) << " stopAnywhere=" << stopAnywhere << " reroutes=" << getNumberStoppingPlaceReroutes(veh) << " alongTheWay=" << Named::getIDSecure(onTheWay) << "\n";
124 : }
125 : #endif
126 : }
127 93984 : if (!ignoreDest && !destVisible && onTheWay == nullptr) {
128 : return nullptr;
129 : }
130 :
131 44003 : const bool destIsFull = destStoppingPlace != nullptr && getLastStepStoppingPlaceOccupancy(destStoppingPlace, &veh) >= getStoppingPlaceCapacity(destStoppingPlace);
132 44003 : if (ignoreDest || destIsFull || onTheWay != nullptr) {
133 : // if the current route ends at the stopping place, the new route will
134 : // also end at the new stopping place
135 59283 : newDestination = (destStoppingPlace != nullptr && &destStoppingPlace->getLane().getEdge() == route.getLastEdge()
136 4087 : && veh.getArrivalPos() >= destStoppingPlace->getBeginLanePosition()
137 4087 : && veh.getArrivalPos() <= destStoppingPlace->getEndLanePosition()
138 30333 : && veh.getStops().size() == 1);
139 :
140 : #ifdef DEBUG_STOPPINGPLACE
141 : if (DEBUGCOND) {
142 : std::cout << SIMTIME << " veh=" << veh.getID()
143 : << " newDest=" << newDestination
144 : << " destIsFull=" << destIsFull
145 : << " onTheWay=" << Named::getIDSecure(onTheWay)
146 : << "\n";
147 : }
148 : #endif
149 : std::map<MSStoppingPlace*, ConstMSEdgeVector> newRoutes;
150 : std::map<MSStoppingPlace*, ConstMSEdgeVector> stopApproaches;
151 29711 : StoppingPlaceParamMap_t weights = collectWeights(veh); // add option to patch values for interdependent values
152 : StoppingPlaceParamMap_t maxValues;
153 267653 : for (auto param : weights) {
154 237942 : maxValues[param.first] = 0.;
155 : }
156 :
157 : // a map stores elegible stopping places
158 : StoppingPlaceMap_t stoppingPlaces;
159 29711 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouter(veh, closedEdges);
160 29711 : const double brakeGap = veh.getBrakeGap();
161 :
162 29711 : if (onTheWay != nullptr) {
163 : // compute new route
164 20 : if (newDestination) {
165 0 : newRoute.push_back(veh.getEdge());
166 : } else {
167 20 : bool valid = evaluateDestination(veh, brakeGap, newDestination, onTheWay, getLastStepStoppingPlaceOccupancy(onTheWay, &veh), 1, router, stoppingPlaces, newRoutes, stopApproaches, maxValues, scores, insertStopIndex, keepCurrentStop);
168 20 : if (!valid) {
169 0 : WRITE_WARNINGF(TL("Stopping place '%' along the way cannot be used by vehicle '%' for unknown reason"), onTheWay->getID(), veh.getID());
170 0 : return nullptr;
171 : }
172 20 : newRoute = newRoutes[onTheWay];
173 : }
174 20 : return onTheWay;
175 : }
176 : int numAlternatives = 0;
177 : std::vector<std::tuple<SUMOTime, MSStoppingPlace*, int>> blockedTimes;
178 29691 : resetStoppingPlaceScores(veh);
179 :
180 29691 : if (destStoppingPlace != nullptr && destIsFull) {
181 29049 : rememberStoppingPlaceScore(veh, destStoppingPlace, "occupied");
182 29049 : rememberBlockedStoppingPlace(veh, destStoppingPlace, &destStoppingPlace->getLane().getEdge() == veh.getEdge());
183 : }
184 29691 : const SUMOTime stoppingPlaceMemory = TIME2STEPS(getWeight(veh, "memory", 600));
185 29691 : const double stoppingPlaceFrustration = getWeight(veh, "frustration", 100);
186 29691 : const double stoppingPlaceKnowledge = getWeight(veh, "knowledge", 0);
187 :
188 126635 : for (int i = 0; i < (int)stoppingPlaceCandidates.size(); ++i) {
189 : // alternative occupancy is randomized (but never full) if invisible
190 : // current destination must be visible at this point
191 96944 : if (!useStoppingPlace(stoppingPlaceCandidates[i].first)) {
192 0 : continue;
193 : }
194 96944 : const bool visible = stoppingPlaceCandidates[i].second || (stoppingPlaceCandidates[i].first == destStoppingPlace && destVisible);
195 96944 : double occupancy = getStoppingPlaceOccupancy(stoppingPlaceCandidates[i].first, &veh);
196 96944 : if (!visible && (stoppingPlaceKnowledge == 0 || stoppingPlaceKnowledge < RandHelper::rand(veh.getRNG()))) {
197 39332 : double capacity = getStoppingPlaceCapacity(stoppingPlaceCandidates[i].first);
198 39332 : const double minOccupancy = MIN2(capacity - NUMERICAL_EPS, (getNumberStoppingPlaceReroutes(veh) * capacity / stoppingPlaceFrustration));
199 : occupancy = RandHelper::rand(minOccupancy, capacity);
200 : // previously visited?
201 39332 : SUMOTime blockedTime = sawBlockedStoppingPlace(veh, stoppingPlaceCandidates[i].first, false);
202 39332 : if (blockedTime >= 0 && SIMSTEP - blockedTime < stoppingPlaceMemory) {
203 : // assume it's still occupied
204 : occupancy = capacity;
205 20991 : blockedTimes.push_back(std::make_tuple(blockedTime, stoppingPlaceCandidates[i].first, i));
206 : #ifdef DEBUG_STOPPINGPLACE
207 : if (DEBUGCOND) {
208 : std::cout << " altStoppingPlace=" << stoppingPlaceCandidates[i].first->getID() << " was blocked at " << time2string(blockedTime) << "\n";
209 : }
210 : #endif
211 : }
212 : }
213 96944 : if (occupancy < getStoppingPlaceCapacity(stoppingPlaceCandidates[i].first)) {
214 21485 : if (evaluateDestination(veh, brakeGap, newDestination, stoppingPlaceCandidates[i].first, occupancy, probs[i], router, stoppingPlaces, newRoutes, stopApproaches, maxValues, scores, insertStopIndex, keepCurrentStop)) {
215 21141 : numAlternatives++;
216 : }
217 75459 : } else if (visible) {
218 : // might only be visible now (i.e. because it's on the other
219 : // side of the street), so we should remember this for later.
220 54256 : rememberStoppingPlaceScore(veh, stoppingPlaceCandidates[i].first, "occupied");
221 54256 : rememberBlockedStoppingPlace(veh, stoppingPlaceCandidates[i].first, &stoppingPlaceCandidates[i].first->getLane().getEdge() == veh.getEdge());
222 : }
223 : }
224 :
225 29691 : if (numAlternatives == 0) {
226 : // use parkingArea with lowest blockedTime
227 21709 : std::sort(blockedTimes.begin(), blockedTimes.end(),
228 15574 : [](std::tuple<SUMOTime, MSStoppingPlace*, int> const & t1, std::tuple<SUMOTime, MSStoppingPlace*, int> const & t2) {
229 15574 : if (std::get<0>(t1) < std::get<0>(t2)) {
230 : return true;
231 : }
232 9074 : if (std::get<0>(t1) == std::get<0>(t2)) {
233 198 : if (std::get<1>(t1)->getID() < std::get<1>(t2)->getID()) {
234 : return true;
235 : }
236 0 : if (std::get<1>(t1)->getID() == std::get<1>(t2)->getID()) {
237 0 : return std::get<2>(t1) < std::get<2>(t2);
238 : }
239 : }
240 : return false;
241 : }
242 : );
243 21709 : for (auto item : blockedTimes) {
244 : MSStoppingPlace* sp = std::get<1>(item);
245 4787 : double prob = probs[std::get<2>(item)];
246 : // all stopping places are occupied. We have no good basis for
247 : // prefering one or the other based on estimated occupancy
248 4787 : double occupancy = RandHelper::rand(getStoppingPlaceCapacity(sp));
249 4787 : if (evaluateDestination(veh, brakeGap, newDestination, sp, occupancy, prob, router, stoppingPlaces, newRoutes, stopApproaches, maxValues, scores, insertStopIndex, keepCurrentStop)) {
250 : #ifdef DEBUG_STOPPINGPLACE
251 : if (DEBUGCOND) {
252 : std::cout << " altStoppingPlace=" << sp->getID() << " targeting occupied stopping place based on blockTime " << STEPS2TIME(std::get<0>(item)) << " among " << blockedTimes.size() << " alternatives\n";
253 : }
254 : #endif
255 : numAlternatives = 1;
256 : break;
257 : }
258 : //std::cout << " candidate=" << item.second->getID() << " observed=" << time2string(item.first) << "\n";
259 : }
260 21709 : if (numAlternatives == 0) {
261 : // take any random target but prefer one that hasn't been visited yet
262 : std::vector<std::pair<SUMOTime, MSStoppingPlace*>> candidates;
263 58570 : for (const StoppingPlaceVisible& stoppingPlaceCandidate : stoppingPlaceCandidates) {
264 41648 : if (stoppingPlaceCandidate.first == destStoppingPlace) {
265 : continue;
266 : }
267 32773 : SUMOTime dummy = sawBlockedStoppingPlace(veh, stoppingPlaceCandidate.first, true);
268 32773 : if (dummy < 0) {
269 : // randomize among the unvisited
270 933 : dummy = -RandHelper::rand(1000000);
271 : }
272 32773 : candidates.push_back(std::make_pair(dummy, stoppingPlaceCandidate.first));
273 : }
274 16922 : std::sort(candidates.begin(), candidates.end(),
275 : [](std::tuple<SUMOTime, MSStoppingPlace*> const & t1, std::tuple<SUMOTime, MSStoppingPlace*> const & t2) {
276 33507 : return std::get<0>(t1) < std::get<0>(t2) || (std::get<0>(t1) == std::get<0>(t2) && std::get<1>(t1)->getID() < std::get<1>(t2)->getID());
277 : }
278 : );
279 17591 : for (auto item : candidates) {
280 16769 : if (evaluateDestination(veh, brakeGap, newDestination, item.second, 0, 1, router, stoppingPlaces, newRoutes, stopApproaches, maxValues, scores, insertStopIndex, keepCurrentStop)) {
281 : #ifdef DEBUG_STOPPINGPLACE
282 : if (DEBUGCOND) {
283 : std::cout << " altStoppingPlace=" << item.second->getID() << " targeting occupied stopping place (based on pure randomness) among " << candidates.size() << " alternatives\n";
284 : }
285 : #endif
286 : numAlternatives = 1;
287 : break;
288 : }
289 : }
290 16922 : }
291 : }
292 59382 : getRouter(veh); // reset closed edges
293 :
294 : #ifdef DEBUG_STOPPINGPLACE
295 : if (DEBUGCOND) {
296 : std::cout << " maxValues=" << joinToString(maxValues, " ", ":") << "\n";
297 : }
298 : #endif
299 :
300 : // minimum cost to get the parking area
301 : double minStoppingPlaceCost = 0.0;
302 :
303 71719 : for (StoppingPlaceMap_t::iterator it = stoppingPlaces.begin(); it != stoppingPlaces.end(); ++it) {
304 : // get the parking values
305 : StoppingPlaceParamMap_t stoppingPlaceValues = it->second;
306 :
307 52510 : if (weights["probability"] > 0. && maxValues["probability"] > 0.) {
308 : // random search should not drive past a usable parking area
309 : bool dominated = false;
310 10482 : double endPos = it->first->getEndLanePosition();
311 10482 : const ConstMSEdgeVector& to1 = stopApproaches[it->first];
312 : assert(to1.size() > 0);
313 32723 : for (auto altSp : stoppingPlaces) {
314 24125 : if (altSp.first == it->first) {
315 : continue;
316 : }
317 15347 : const ConstMSEdgeVector& to2 = stopApproaches[altSp.first];
318 : assert(to2.size() > 0);
319 15347 : if (to1.size() > to2.size()) {
320 6322 : if (std::equal(to2.begin(), to2.end(), to1.begin())) {
321 : // other target lies on the route to the current candidate
322 : dominated = true;
323 : //std::cout << SIMTIME << " rrP veh=" << veh.getID() << " full=" << destParkArea->getID() << " cand=" << it->first->getID() << " onTheWay=" << altPa.first->getID() << "\n";
324 : break;
325 : }
326 9025 : } else if (to1 == to2 && endPos > altSp.first->getEndLanePosition()) {
327 : // other target is on the same edge but ahead of the current candidate
328 : dominated = true;
329 : //std::cout << SIMTIME << " rrP veh=" << veh.getID() << " full=" << destParkArea->getID() << " cand=" << it->first->getID() << " sameEdge=" << altPa.first->getID() << "\n";
330 : break;
331 : }
332 : }
333 : double prob = 0;
334 : if (!dominated) {
335 8598 : prob = RandHelper::rand(stoppingPlaceValues["probability"], veh.getRNG());
336 8598 : stoppingPlaceValues["probability"] = 1.0 - prob / maxValues["probability"];
337 : } else {
338 : // worst probability score
339 1884 : stoppingPlaceValues["probability"] = 1.0;
340 : }
341 : } else {
342 : // value takes no effect due to weight=0
343 31546 : stoppingPlaceValues["probability"] = 0;
344 : }
345 :
346 : // get the parking area cost
347 42028 : double stoppingPlaceCost = getTargetValue(stoppingPlaceValues, maxValues, weights, myNormParams, myInvertParams);
348 42028 : rememberStoppingPlaceScore(veh, it->first, toString(stoppingPlaceCost));
349 :
350 : // get the parking area with minimum cost
351 42028 : if (nearStoppingPlace == nullptr || stoppingPlaceCost < minStoppingPlaceCost) {
352 : minStoppingPlaceCost = stoppingPlaceCost;
353 32910 : nearStoppingPlace = it->first;
354 32910 : newRoute = newRoutes[nearStoppingPlace];
355 : }
356 : #ifdef DEBUG_STOPPINGPLACE
357 : if (DEBUGCOND) {
358 : std::cout << " altStoppingPlace=" << it->first->getID() << " score=" << stoppingPlaceCost << " vals=" << joinToString(stoppingPlaceValues, " ", ":") << "\n";
359 : }
360 : #endif
361 : }
362 : // expose the scores of the best solution
363 29691 : if (nearStoppingPlace != nullptr) {
364 259997 : for (auto component : stoppingPlaces[nearStoppingPlace]) {
365 231128 : scores[component.first] = component.second;
366 : }
367 : }
368 29691 : setNumberStoppingPlaceReroutes(veh, getNumberStoppingPlaceReroutes(veh) + 1);
369 29691 : } else {
370 : #ifdef DEBUG_STOPPINGPLACE
371 : if (DEBUGCOND) {
372 : std::cout << SIMTIME << " veh=" << veh.getID() << " dest=" << destStoppingPlace->getID() << " sufficient space\n";
373 : }
374 : #endif
375 : }
376 :
377 : #ifdef DEBUG_STOPPINGPLACE
378 : if (DEBUGCOND) {
379 : std::cout << " stoppingPlaceResult=" << Named::getIDSecure(nearStoppingPlace) << "\n";
380 : }
381 : #endif
382 43983 : return nearStoppingPlace;
383 : }
384 :
385 :
386 : bool
387 43061 : MSStoppingPlaceRerouter::evaluateDestination(SUMOVehicle& veh, double brakeGap, bool newDestination, MSStoppingPlace* alternative,
388 : double occupancy, double prob, SUMOAbstractRouter<MSEdge, SUMOVehicle>& router, StoppingPlaceMap_t& stoppingPlaces,
389 : std::map<MSStoppingPlace*, ConstMSEdgeVector>& newRoutes, std::map<MSStoppingPlace*, ConstMSEdgeVector>& stoppingPlaceApproaches,
390 : StoppingPlaceParamMap_t& maxValues, StoppingPlaceParamMap_t& addInput, const int insertStopIndex, const bool keepCurrentStop) {
391 :
392 : // a map stores the stopping place values
393 : StoppingPlaceParamMap_t stoppingPlaceValues;
394 43061 : const SUMOTime now = SIMSTEP;
395 :
396 43061 : const MSRoute& route = veh.getRoute();
397 43061 : const RGBColor& c = route.getColor();
398 43061 : const MSEdge* stoppingPlaceEdge = &(alternative->getLane().getEdge());
399 :
400 43061 : const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
401 :
402 : // Compute the route from the current edge to the stopping place edge
403 : ConstMSEdgeVector edgesToStop;
404 : ConstMSEdgeVector edgesUpstream;
405 43061 : const double targetPos = alternative->getLastFreePos(veh);
406 43061 : MSRouteIterator rerouteOriginIt = determineRerouteOrigin(veh, insertStopIndex);
407 43061 : double posOnLane = veh.getPositionOnLane();
408 43061 : if (insertStopIndex > 0) {
409 : posOnLane = 0.;
410 : // determine preceding edges
411 0 : for (MSRouteIterator it = veh.getCurrentRouteEdge(); it != rerouteOriginIt; ++it) {
412 : if (it != rerouteOriginIt) {
413 0 : edgesUpstream.push_back(*it);
414 : }
415 : }
416 : }
417 43061 : const MSEdge* rerouteOrigin = *rerouteOriginIt;
418 43061 : router.compute(rerouteOrigin, posOnLane, stoppingPlaceEdge, targetPos, &veh, now, edgesToStop, true);
419 43061 : if (edgesToStop.size() > 0) {
420 : // Compute the route from the stopping place edge to the end of the route
421 42585 : if (insertStopIndex == 0 && rerouteOrigin != veh.getEdge()) {
422 5 : edgesToStop.insert(edgesToStop.begin(), veh.getEdge());
423 : }
424 : // prepend preceding edges
425 : std::reverse(edgesUpstream.begin(), edgesUpstream.end());
426 42585 : for (auto edge : edgesUpstream) {
427 0 : edgesToStop.insert(edgesToStop.begin(), edge);
428 : }
429 : ConstMSEdgeVector edgesFromStop;
430 42585 : stoppingPlaceApproaches[alternative] = edgesToStop;
431 :
432 42585 : const MSEdge* nextDestination = route.getLastEdge();
433 42585 : double nextPos = veh.getArrivalPos();
434 42585 : int nextDestinationIndex = route.size() - 1;
435 42585 : if (!newDestination) {
436 41168 : std::vector<std::pair<int, double> > stopIndices = veh.getStopIndices();
437 41168 : int nextDestStopIndex = 1 + insertStopIndex;
438 41168 : if (!keepCurrentStop) {
439 0 : nextDestStopIndex++;
440 : }
441 41168 : if ((int)stopIndices.size() > nextDestStopIndex) {
442 354 : nextDestinationIndex = stopIndices[nextDestStopIndex].first;
443 354 : nextDestination = route.getEdges()[nextDestinationIndex];
444 354 : nextPos = stopIndices[nextDestStopIndex].second;
445 : }
446 41168 : router.compute(stoppingPlaceEdge, targetPos, nextDestination, nextPos, &veh, now, edgesFromStop, true);
447 41168 : }
448 42585 : if (edgesFromStop.size() > 0 || newDestination) {
449 42580 : stoppingPlaceValues["probability"] = prob;
450 42580 : if (stoppingPlaceValues["probability"] > maxValues["probability"]) {
451 29135 : maxValues["probability"] = stoppingPlaceValues["probability"];
452 : }
453 42580 : stoppingPlaceValues["capacity"] = getStoppingPlaceCapacity(alternative);
454 42580 : stoppingPlaceValues["absfreespace"] = stoppingPlaceValues["capacity"] - occupancy;
455 : // if capacity = 0 then absfreespace and relfreespace are also 0
456 85032 : stoppingPlaceValues["relfreespace"] = stoppingPlaceValues["absfreespace"] / MAX2(1.0, stoppingPlaceValues["capacity"]);
457 42580 : MSRoute routeToPark(route.getID() + "!to" + myParamPrefix + "#1", edgesToStop, false,
458 85160 : &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), route.getStops());
459 :
460 : // The distance from the current edge to the new parking area
461 42580 : double toPos = alternative->getBeginLanePosition();
462 42580 : if (&alternative->getLane().getEdge() == veh.getEdge()) {
463 17156 : toPos = MAX2(veh.getPositionOnLane(), toPos);
464 : }
465 42580 : stoppingPlaceValues["distanceto"] = routeToPark.getDistanceBetween(veh.getPositionOnLane(), toPos,
466 42580 : routeToPark.begin(), routeToPark.end() - 1, includeInternalLengths);
467 :
468 42580 : if (stoppingPlaceValues["distanceto"] == std::numeric_limits<double>::max()) {
469 0 : WRITE_WARNINGF(TL("Invalid distance computation for vehicle '%' to stopping place '%' at time=%."),
470 : veh.getID(), alternative->getID(), time2string(now));
471 : }
472 42580 : const double endPos = alternative->getLastFreePos(veh, veh.getPositionOnLane() + brakeGap);
473 42580 : const double distToEnd = stoppingPlaceValues["distanceto"] - toPos + endPos;
474 :
475 42580 : if (distToEnd < brakeGap) {
476 344 : rememberStoppingPlaceScore(veh, alternative, "tooClose");
477 344 : return false;
478 : }
479 :
480 : // The time to reach the new stopping place
481 42236 : const double correctionLastEdge = ((alternative->getLane().getLength() - alternative->getEndLanePosition()) / alternative->getLane().getVehicleMaxSpeed(&veh));
482 42236 : const double correctionFirstEdge = veh.getPositionOnLane() / edgesToStop.front()->getVehicleMaxSpeed(&veh);
483 :
484 42236 : stoppingPlaceValues["timeto"] = router.recomputeCosts(edgesToStop, &veh, SIMSTEP) - correctionLastEdge - correctionFirstEdge;
485 42236 : ConstMSEdgeVector newEdges = edgesToStop;
486 42236 : if (newDestination) {
487 1417 : stoppingPlaceValues["distancefrom"] = 0;
488 1417 : stoppingPlaceValues["timefrom"] = 0;
489 : } else {
490 40819 : MSRoute routeFromPark(route.getID() + "!from" + myParamPrefix + "#1", edgesFromStop, false,
491 81638 : &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), route.getStops());
492 : // The distance from the new parking area to the end of the route
493 40819 : stoppingPlaceValues["distancefrom"] = routeFromPark.getDistanceBetween(alternative->getBeginLanePosition(), routeFromPark.getLastEdge()->getLength(),
494 40819 : routeFromPark.begin(), routeFromPark.end() - 1, includeInternalLengths);
495 40819 : if (stoppingPlaceValues["distancefrom"] == std::numeric_limits<double>::max()) {
496 0 : WRITE_WARNINGF(TL("Invalid distance computation for vehicle '%' from stopping place '%' at time=%."),
497 : veh.getID(), alternative->getID(), time2string(SIMSTEP));
498 : }
499 : // The time to reach this area
500 40819 : stoppingPlaceValues["timefrom"] = router.recomputeCosts(edgesFromStop, &veh, SIMSTEP) - (alternative->getEndLanePosition() / alternative->getLane().getSpeedLimit());
501 40819 : newEdges.insert(newEdges.end(), edgesFromStop.begin() + 1, edgesFromStop.end());
502 40819 : newEdges.insert(newEdges.end(), route.begin() + nextDestinationIndex + 1, route.end());
503 40819 : }
504 :
505 : // add some additional/custom target function components
506 42236 : if (!evaluateCustomComponents(veh, brakeGap, newDestination, alternative, occupancy, prob, router, stoppingPlaceValues, stoppingPlaceApproaches[alternative], newEdges, maxValues, addInput)) {
507 : return false;
508 : }
509 42236 : if (!myCheckValidity || validComponentValues(stoppingPlaceValues)) {
510 42048 : updateMaxValues(stoppingPlaceValues, maxValues);
511 42048 : stoppingPlaces[alternative] = stoppingPlaceValues;
512 42048 : newRoutes[alternative] = newEdges;
513 : return true;
514 : } else {
515 : return false;
516 : }
517 42580 : } else {
518 5 : rememberStoppingPlaceScore(veh, alternative, "unreachable");
519 : }
520 42585 : } else {
521 952 : rememberStoppingPlaceScore(veh, alternative, "unreachable");
522 : }
523 : // unreachable
524 : return false;
525 43061 : }
526 :
527 :
528 : bool
529 41692 : MSStoppingPlaceRerouter::evaluateCustomComponents(SUMOVehicle& /*veh*/, double /*brakeGap*/, bool /*newDestination*/,
530 : MSStoppingPlace* /*alternative*/, double /*occupancy*/, double /*prob*/, SUMOAbstractRouter<MSEdge, SUMOVehicle>& /*router*/,
531 : StoppingPlaceParamMap_t& /*stoppingPlaceValues*/, ConstMSEdgeVector& /*newRoute*/, ConstMSEdgeVector& /*stoppingPlaceApproach*/,
532 : StoppingPlaceParamMap_t& /*maxValues*/, StoppingPlaceParamMap_t& /*addInput*/) {
533 41692 : return true;
534 : }
535 :
536 :
537 : bool
538 0 : MSStoppingPlaceRerouter::validComponentValues(StoppingPlaceParamMap_t& /* stoppingPlaceValues */) {
539 0 : return true;
540 : }
541 :
542 :
543 : bool
544 96484 : MSStoppingPlaceRerouter::useStoppingPlace(MSStoppingPlace* /* stoppingPlace */) {
545 96484 : return true;
546 : }
547 :
548 :
549 : SUMOAbstractRouter<MSEdge, SUMOVehicle>&
550 59148 : MSStoppingPlaceRerouter::getRouter(SUMOVehicle& veh, const Prohibitions& prohibited) {
551 59148 : return MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), prohibited);
552 : }
553 :
554 :
555 : MSStoppingPlaceRerouter::StoppingPlaceParamMap_t
556 29711 : MSStoppingPlaceRerouter::collectWeights(SUMOVehicle& veh) {
557 : MSStoppingPlaceRerouter::StoppingPlaceParamMap_t result;
558 29711 : myEvalParams["distanceto"] = getWeight(veh, "distance.weight", myEvalParams["distanceto"]);
559 267653 : for (auto evalParam : myEvalParams) {
560 237942 : result[evalParam.first] = getWeight(veh, evalParam.first + ".weight", evalParam.second);
561 : }
562 29711 : result["probability"] = getWeight(veh, "probability.weight", 0.);
563 29711 : return result;
564 : }
565 :
566 :
567 : double
568 604350 : MSStoppingPlaceRerouter::getWeight(SUMOVehicle& veh, const std::string param, const double defaultWeight, const bool warn) {
569 : // get custom vehicle parameter
570 604350 : const std::string key = myParamPrefix + "." + param;
571 604350 : if (veh.getParameter().hasParameter(key)) {
572 : try {
573 88 : return StringUtils::toDouble(veh.getParameter().getParameter(key, "-1"));
574 0 : } catch (...) {
575 0 : WRITE_WARNINGF(TL("Invalid value '%' for vehicle parameter '%'"), veh.getParameter().getParameter(key, "-1"), key);
576 0 : }
577 : } else {
578 : // get custom vType parameter
579 604306 : if (veh.getVehicleType().getParameter().hasParameter(key)) {
580 : try {
581 33190 : return StringUtils::toDouble(veh.getVehicleType().getParameter().getParameter(key, "-1"));
582 0 : } catch (...) {
583 0 : WRITE_WARNINGF(TL("Invalid value '%' for vType parameter '%'"), veh.getVehicleType().getParameter().getParameter(key, "-1"), key);
584 0 : }
585 : }
586 : }
587 587711 : if (warn) {
588 0 : WRITE_MESSAGEF("Vehicle '%' does not supply vehicle parameter '%'. Using default of %\n", veh.getID(), key, toString(defaultWeight));
589 : }
590 587711 : return defaultWeight;
591 : }
592 :
593 :
594 : void
595 42048 : MSStoppingPlaceRerouter::updateMaxValues(StoppingPlaceParamMap_t& stoppingPlaceValues, StoppingPlaceParamMap_t& maxValues) {
596 379144 : for (auto it = maxValues.begin(); it != maxValues.end(); ++it) {
597 337096 : if (stoppingPlaceValues[it->first] > it->second) {
598 234269 : it->second = stoppingPlaceValues[it->first];
599 : }
600 : }
601 42048 : }
602 :
603 :
604 : double
605 42028 : MSStoppingPlaceRerouter::getTargetValue(const StoppingPlaceParamMap_t& absValues, const StoppingPlaceParamMap_t& maxValues, const StoppingPlaceParamMap_t& weights, const StoppingPlaceParamSwitchMap_t& norm, const StoppingPlaceParamSwitchMap_t& invert) {
606 : double cost = 0.;
607 378964 : for (StoppingPlaceParamMap_t::const_iterator sc = absValues.begin(); sc != absValues.end(); ++sc) {
608 336936 : double weight = weights.at(sc->first);
609 336936 : double val = sc->second;
610 336936 : if (norm.at(sc->first) && maxValues.at(sc->first) > 0.) {
611 291541 : val /= maxValues.at(sc->first);
612 : }
613 336936 : cost += (invert.at(sc->first)) ? weight * (1. - val) : weight * val;
614 : }
615 42028 : return cost;
616 : }
617 :
618 :
619 : /****************************************************************************/
|