Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file 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 DEBUGCOND (veh.isSelected())
34 :
35 :
36 : ///@brief Constructor
37 3452 : MSStoppingPlaceRerouter::MSStoppingPlaceRerouter(SumoXMLTag stoppingType, std::string paramPrefix, bool checkValidity, bool checkVisibility, StoppingPlaceParamMap_t addEvalParams, StoppingPlaceParamSwitchMap_t addInvertParams) :
38 3452 : myStoppingType(stoppingType), myParamPrefix(paramPrefix), myCheckValidity(checkValidity), myConsiderDestVisibility(checkVisibility) {
39 31068 : myEvalParams = { {"probability", 0.}, {"capacity", 0.}, {"timefrom", 0.}, {"timeto", 0.}, {"distancefrom", 0.}, {"distanceto", 1.}, {"absfreespace", 0.}, {"relfreespace", 0.}, };
40 31068 : myInvertParams = { {"probability", false}, { "capacity", true }, { "timefrom", false }, { "timeto", false }, { "distancefrom", false }, { "distanceto", false }, { "absfreespace", true }, { "relfreespace", true } };
41 3580 : for (auto param : addEvalParams) {
42 128 : myEvalParams[param.first] = param.second;
43 256 : myInvertParams[param.first] = (addInvertParams.count(param.first) > 0) ? addInvertParams[param.first] : false;
44 : }
45 31196 : for (auto param : myEvalParams) {
46 27744 : myNormParams.insert({param.first, param.first != "probability"});
47 : }
48 3580 : }
49 :
50 : MSStoppingPlace*
51 58598 : MSStoppingPlaceRerouter::reroute(std::vector<StoppingPlaceVisible>& stoppingPlaceCandidates, const std::vector<double>& probs, SUMOVehicle& veh, bool& newDestination, ConstMSEdgeVector& newRoute, StoppingPlaceParamMap_t& scores, const MSEdgeVector& closedEdges) {
52 : // Reroute destination from initial stopping place to an alternative stopping place
53 : // if the following conditions are met:
54 : // - next stop target is a stopping place of the right type
55 : // - target is included in the current alternative set
56 : // - target is visibly full
57 : // Any stopping places that are visibly full at the current location are
58 : // committed to the stopping place memory corresponding to their type
59 :
60 58598 : MSStoppingPlace* nearStoppingPlace = nullptr;
61 :
62 : // get vehicle params
63 : MSStoppingPlace* destStoppingPlace = nullptr;
64 : bool destVisible = false;
65 58598 : if (myStoppingType == SUMO_TAG_PARKING_AREA) {
66 58538 : destStoppingPlace = veh.getNextParkingArea();
67 58538 : if (destStoppingPlace == nullptr) {
68 : // not driving towards the right type of stop
69 : return nullptr;
70 : }
71 49517 : destVisible = (&destStoppingPlace->getLane().getEdge() == veh.getEdge());
72 : // if the vehicle is on the destination stop edge it is always visible
73 116103 : for (auto stoppingPlace : stoppingPlaceCandidates) {
74 79914 : if (stoppingPlace.first == destStoppingPlace && stoppingPlace.second) {
75 : destVisible = true;
76 : break;
77 : }
78 : }
79 : }
80 49577 : const MSRoute& route = veh.getRoute();
81 :
82 49577 : MSStoppingPlace* onTheWay = nullptr;
83 49577 : const int stopAnywhere = (int)getWeight(veh, "anywhere", -1);
84 : // check whether we are ready to accept any free stopping place along the
85 : // way to our destination
86 49577 : if (stopAnywhere < 0 || stopAnywhere > getNumberStoppingPlaceReroutes(veh)) {
87 49542 : if (!destVisible) {
88 : // cannot determine destination occupancy, only register visibly full
89 73431 : for (const StoppingPlaceVisible& stoppingPlace : stoppingPlaceCandidates) {
90 47178 : if (stoppingPlace.second && getLastStepStoppingPlaceOccupancy(stoppingPlace.first) >= getStoppingPlaceCapacity(stoppingPlace.first)) {
91 5579 : rememberStoppingPlaceScore(veh, stoppingPlace.first, "occupied");
92 5579 : rememberBlockedStoppingPlace(veh, stoppingPlace.first, &stoppingPlace.first->getLane().getEdge() == veh.getEdge());
93 : }
94 : }
95 : #ifdef DEBUG_STOPPINGPLACE
96 : if (DEBUGCOND) {
97 : //std::cout << SIMTIME << " << " veh=" << veh.getID()
98 : // << " dest=" << ((destStoppingPlace == nullptr)? "null" : destStoppingPlace->getID()) << " stopAnywhere=" << stopAnywhere << "reroutes=" << getNumberStoppingPlaceReroutes(veh) << " stay on original route\n";
99 : }
100 : #endif
101 : }
102 : } else {
103 : double bestDist = std::numeric_limits<double>::max();
104 35 : const double brakeGap = veh.getBrakeGap(true);
105 200 : for (StoppingPlaceVisible& item : stoppingPlaceCandidates) {
106 165 : if (item.second) {
107 70 : if (&item.first->getLane().getEdge() == veh.getEdge()
108 70 : && getLastStepStoppingPlaceOccupancy(item.first) < getStoppingPlaceCapacity(item.first)) {
109 25 : const double distToStart = item.first->getBeginLanePosition() - veh.getPositionOnLane();
110 25 : const double distToEnd = item.first->getEndLanePosition() - veh.getPositionOnLane();
111 25 : if (distToEnd > brakeGap) {
112 40 : rememberStoppingPlaceScore(veh, item.first, "dist=" + toString(distToStart));
113 20 : if (distToStart < bestDist) {
114 : bestDist = distToStart;
115 20 : onTheWay = item.first;
116 : }
117 : } else {
118 10 : rememberStoppingPlaceScore(veh, item.first, "tooClose");
119 : }
120 : }
121 : }
122 : }
123 : #ifdef DEBUG_STOPPINGPLACE
124 : if (DEBUGCOND) {
125 : std::cout << SIMTIME << " veh=" << veh.getID()
126 : << " dest=" << ((destStoppingPlace == nullptr) ? "null" : destStoppingPlace->getID()) << " stopAnywhere=" << stopAnywhere << " reroutes=" << getNumberStoppingPlaceReroutes(veh) << " alongTheWay=" << Named::getIDSecure(onTheWay) << "\n";
127 : }
128 : #endif
129 : }
130 49577 : if (myConsiderDestVisibility && !destVisible && onTheWay == nullptr) {
131 : return nullptr;
132 : }
133 :
134 23379 : if (!myConsiderDestVisibility || getLastStepStoppingPlaceOccupancy(destStoppingPlace) >= getStoppingPlaceCapacity(destStoppingPlace) || onTheWay != nullptr) {
135 : // if the current route ends at the stopping place, the new route will
136 : // also end at the new stopping place
137 24426 : newDestination = (destStoppingPlace != nullptr && &destStoppingPlace->getLane().getEdge() == route.getLastEdge()
138 3489 : && veh.getArrivalPos() >= destStoppingPlace->getBeginLanePosition()
139 3489 : && veh.getArrivalPos() <= destStoppingPlace->getEndLanePosition()
140 12860 : && veh.getStops().size() == 1);
141 :
142 : #ifdef DEBUG_STOPPINGPLACE
143 : if (DEBUGCOND) {
144 : std::cout << SIMTIME << " veh=" << veh.getID()
145 : << " newDest=" << newDestination
146 : << " onTheWay=" << Named::getIDSecure(onTheWay)
147 : << "\n";
148 : }
149 : #endif
150 : std::map<MSStoppingPlace*, ConstMSEdgeVector> newRoutes;
151 : std::map<MSStoppingPlace*, ConstMSEdgeVector> stopApproaches;
152 12243 : StoppingPlaceParamMap_t weights = collectWeights(veh); // add option to patch values for interdependent values
153 : StoppingPlaceParamMap_t maxValues;
154 110307 : for (auto param : weights) {
155 98064 : maxValues[param.first] = 0.;
156 : }
157 :
158 : // a map stores elegible stopping places
159 : StoppingPlaceMap_t stoppingPlaces;
160 12243 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = getRouter(veh, closedEdges);
161 12243 : const double brakeGap = veh.getBrakeGap(true);
162 :
163 12243 : if (onTheWay != nullptr) {
164 : // compute new route
165 20 : if (newDestination) {
166 0 : newRoute.push_back(veh.getEdge());
167 : } else {
168 20 : bool valid = evaluateDestination(veh, brakeGap, newDestination, onTheWay, getLastStepStoppingPlaceOccupancy(onTheWay), 1, router, stoppingPlaces, newRoutes, stopApproaches, maxValues, scores);
169 20 : if (!valid) {
170 0 : WRITE_WARNINGF(TL("Stopping place '%' along the way cannot be used by vehicle '%' for unknown reason"), onTheWay->getID(), veh.getID());
171 0 : return nullptr;
172 : }
173 20 : newRoute = newRoutes[onTheWay];
174 : }
175 20 : return onTheWay;
176 : }
177 : int numAlternatives = 0;
178 : std::vector<std::tuple<SUMOTime, MSStoppingPlace*, int>> blockedTimes;
179 12223 : resetStoppingPlaceScores(veh);
180 :
181 12223 : if (destStoppingPlace != nullptr) {
182 12163 : rememberStoppingPlaceScore(veh, destStoppingPlace, "occupied");
183 12163 : rememberBlockedStoppingPlace(veh, destStoppingPlace, &destStoppingPlace->getLane().getEdge() == veh.getEdge());
184 : }
185 12223 : const SUMOTime stoppingPlaceMemory = TIME2STEPS(getWeight(veh, "memory", 600));
186 12223 : const double stoppingPlaceFrustration = getWeight(veh, "frustration", 100);
187 12223 : const double stoppingPlaceKnowledge = getWeight(veh, "knowledge", 0);
188 :
189 63250 : for (int i = 0; i < (int)stoppingPlaceCandidates.size(); ++i) {
190 : // alternative occupancy is randomized (but never full) if invisible
191 : // current destination must be visible at this point
192 51027 : if (!useStoppingPlace(stoppingPlaceCandidates[i].first)) {
193 0 : continue;
194 : }
195 51027 : const bool visible = stoppingPlaceCandidates[i].second || (stoppingPlaceCandidates[i].first == destStoppingPlace && destVisible);
196 51027 : double occupancy = getStoppingPlaceOccupancy(stoppingPlaceCandidates[i].first);
197 51027 : if (!visible && (stoppingPlaceKnowledge == 0 || stoppingPlaceKnowledge < RandHelper::rand(veh.getRNG()))) {
198 36410 : double capacity = getStoppingPlaceCapacity(stoppingPlaceCandidates[i].first);
199 36410 : const double minOccupancy = MIN2(capacity - NUMERICAL_EPS, (getNumberStoppingPlaceReroutes(veh) * capacity / stoppingPlaceFrustration));
200 : occupancy = RandHelper::rand(minOccupancy, capacity);
201 : // previously visited?
202 36410 : SUMOTime blockedTime = sawBlockedStoppingPlace(veh, stoppingPlaceCandidates[i].first, false);
203 36410 : if (blockedTime >= 0 && SIMSTEP - blockedTime < stoppingPlaceMemory) {
204 : // assume it's still occupied
205 : occupancy = capacity;
206 19409 : blockedTimes.push_back(std::make_tuple(blockedTime, stoppingPlaceCandidates[i].first, i));
207 : #ifdef DEBUG_STOPPINGPLACE
208 : if (DEBUGCOND) {
209 : std::cout << " altStoppingPlace=" << stoppingPlaceCandidates[i].first->getID() << " was blocked at " << time2string(blockedTime) << "\n";
210 : }
211 : #endif
212 : }
213 : }
214 51027 : if (occupancy < getStoppingPlaceCapacity(stoppingPlaceCandidates[i].first)) {
215 18286 : if (evaluateDestination(veh, brakeGap, newDestination, stoppingPlaceCandidates[i].first, occupancy, probs[i], router, stoppingPlaces, newRoutes, stopApproaches, maxValues, scores)) {
216 17968 : numAlternatives++;
217 : }
218 32741 : } else if (visible) {
219 : // might only be visible now (i.e. because it's on the other
220 : // side of the street), so we should remember this for later.
221 13142 : rememberStoppingPlaceScore(veh, stoppingPlaceCandidates[i].first, "occupied");
222 13142 : rememberBlockedStoppingPlace(veh, stoppingPlaceCandidates[i].first, &stoppingPlaceCandidates[i].first->getLane().getEdge() == veh.getEdge());
223 : }
224 : }
225 :
226 12223 : if (numAlternatives == 0) {
227 : // use parkingArea with lowest blockedTime
228 5812 : std::sort(blockedTimes.begin(), blockedTimes.end(),
229 14961 : [](std::tuple<SUMOTime, MSStoppingPlace*, int> const & t1, std::tuple<SUMOTime, MSStoppingPlace*, int> const & t2) {
230 14961 : if (std::get<0>(t1) < std::get<0>(t2)) {
231 : return true;
232 : }
233 8631 : if (std::get<0>(t1) == std::get<0>(t2)) {
234 3 : if (std::get<1>(t1)->getID() < std::get<1>(t2)->getID()) {
235 : return true;
236 : }
237 0 : if (std::get<1>(t1)->getID() == std::get<1>(t2)->getID()) {
238 0 : return std::get<2>(t1) < std::get<2>(t2);
239 : }
240 : }
241 : return false;
242 : }
243 : );
244 5812 : for (auto item : blockedTimes) {
245 : MSStoppingPlace* sp = std::get<1>(item);
246 4538 : double prob = probs[std::get<2>(item)];
247 : // all stopping places are occupied. We have no good basis for
248 : // prefering one or the other based on estimated occupancy
249 4538 : double occupancy = RandHelper::rand(getStoppingPlaceCapacity(sp));
250 4538 : if (evaluateDestination(veh, brakeGap, newDestination, sp, occupancy, prob, router, stoppingPlaces, newRoutes, stopApproaches, maxValues, scores)) {
251 : #ifdef DEBUG_STOPPINGPLACE
252 : if (DEBUGCOND) {
253 : std::cout << " altStoppingPlace=" << sp->getID() << " targeting occupied stopping place based on blockTime " << STEPS2TIME(std::get<0>(item)) << " among " << blockedTimes.size() << " alternatives\n";
254 : }
255 : #endif
256 : numAlternatives = 1;
257 : break;
258 : }
259 : //std::cout << " candidate=" << item.second->getID() << " observed=" << time2string(item.first) << "\n";
260 : }
261 5812 : if (numAlternatives == 0) {
262 : // take any random target but prefer one that hasn't been visited yet
263 : std::vector<std::pair<SUMOTime, MSStoppingPlace*>> candidates;
264 3914 : for (const StoppingPlaceVisible& stoppingPlaceCandidate : stoppingPlaceCandidates) {
265 2640 : if (stoppingPlaceCandidate.first == destStoppingPlace) {
266 : continue;
267 : }
268 1718 : SUMOTime dummy = sawBlockedStoppingPlace(veh, stoppingPlaceCandidate.first, true);
269 1718 : if (dummy < 0) {
270 : // randomize among the unvisited
271 860 : dummy = -RandHelper::rand(1000000);
272 : }
273 1718 : candidates.push_back(std::make_pair(dummy, stoppingPlaceCandidate.first));
274 : }
275 1274 : std::sort(candidates.begin(), candidates.end(),
276 : [](std::tuple<SUMOTime, MSStoppingPlace*> const & t1, std::tuple<SUMOTime, MSStoppingPlace*> const & t2) {
277 2594 : 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());
278 : }
279 : );
280 1737 : for (auto item : candidates) {
281 998 : if (evaluateDestination(veh, brakeGap, newDestination, item.second, 0, 1, router, stoppingPlaces, newRoutes, stopApproaches, maxValues, scores)) {
282 : #ifdef DEBUG_STOPPINGPLACE
283 : if (DEBUGCOND) {
284 : std::cout << " altStoppingPlace=" << item.second->getID() << " targeting occupied stopping place (based on pure randomness) among " << candidates.size() << " alternatives\n";
285 : }
286 : #endif
287 : numAlternatives = 1;
288 : break;
289 : }
290 : }
291 1274 : }
292 : }
293 12223 : getRouter(veh); // reset closed edges
294 :
295 : #ifdef DEBUG_STOPPINGPLACE
296 : if (DEBUGCOND) {
297 : std::cout << " maxValues=" << joinToString(maxValues, " ", ":") << "\n";
298 : }
299 : #endif
300 :
301 : // minimum cost to get the parking area
302 : double minStoppingPlaceCost = 0.0;
303 :
304 35264 : for (StoppingPlaceMap_t::iterator it = stoppingPlaces.begin(); it != stoppingPlaces.end(); ++it) {
305 : // get the parking values
306 : StoppingPlaceParamMap_t stoppingPlaceValues = it->second;
307 :
308 33471 : if (weights["probability"] > 0. && maxValues["probability"] > 0.) {
309 : // random search should not drive past a usable parking area
310 : bool dominated = false;
311 10430 : double endPos = it->first->getEndLanePosition();
312 10430 : const ConstMSEdgeVector& to1 = stopApproaches[it->first];
313 : assert(to1.size() > 0);
314 32644 : for (auto altSp : stoppingPlaces) {
315 24064 : if (altSp.first == it->first) {
316 : continue;
317 : }
318 15307 : const ConstMSEdgeVector& to2 = stopApproaches[altSp.first];
319 : assert(to2.size() > 0);
320 15307 : if (to1.size() > to2.size()) {
321 6268 : if (std::equal(to2.begin(), to2.end(), to1.begin())) {
322 : // other target lies on the route to the current candidate
323 : dominated = true;
324 : //std::cout << SIMTIME << " rrP veh=" << veh.getID() << " full=" << destParkArea->getID() << " cand=" << it->first->getID() << " onTheWay=" << altPa.first->getID() << "\n";
325 : break;
326 : }
327 9039 : } else if (to1 == to2 && endPos > altSp.first->getEndLanePosition()) {
328 : // other target is on the same edge but ahead of the current candidate
329 : dominated = true;
330 : //std::cout << SIMTIME << " rrP veh=" << veh.getID() << " full=" << destParkArea->getID() << " cand=" << it->first->getID() << " sameEdge=" << altPa.first->getID() << "\n";
331 : break;
332 : }
333 : }
334 : double prob = 0;
335 : if (!dominated) {
336 8580 : prob = RandHelper::rand(stoppingPlaceValues["probability"], veh.getRNG());
337 8580 : stoppingPlaceValues["probability"] = 1.0 - prob / maxValues["probability"];
338 : } else {
339 : // worst probability score
340 1850 : stoppingPlaceValues["probability"] = 1.0;
341 : }
342 : } else {
343 : // value takes no effect due to weight=0
344 12611 : stoppingPlaceValues["probability"] = 0;
345 : }
346 :
347 : // get the parking area cost
348 23041 : double stoppingPlaceCost = getTargetValue(stoppingPlaceValues, maxValues, weights, myNormParams, myInvertParams);
349 23041 : rememberStoppingPlaceScore(veh, it->first, toString(stoppingPlaceCost));
350 :
351 : // get the parking area with minimum cost
352 23041 : if (nearStoppingPlace == nullptr || stoppingPlaceCost < minStoppingPlaceCost) {
353 : minStoppingPlaceCost = stoppingPlaceCost;
354 15220 : nearStoppingPlace = it->first;
355 15220 : newRoute = newRoutes[nearStoppingPlace];
356 : }
357 : #ifdef DEBUG_STOPPINGPLACE
358 : if (DEBUGCOND) {
359 : std::cout << " altStoppingPlace=" << it->first->getID() << " score=" << stoppingPlaceCost << " vals=" << joinToString(stoppingPlaceValues, " ", ":") << "\n";
360 : }
361 : #endif
362 : }
363 : // expose the scores of the best solution
364 12223 : if (nearStoppingPlace != nullptr) {
365 103452 : for (auto component : stoppingPlaces[nearStoppingPlace]) {
366 91968 : scores[component.first] = component.second;
367 : }
368 : }
369 12223 : setNumberStoppingPlaceReroutes(veh, getNumberStoppingPlaceReroutes(veh) + 1);
370 12223 : } else {
371 : #ifdef DEBUG_STOPPINGPLACE
372 : if (DEBUGCOND) {
373 : std::cout << SIMTIME << " veh=" << veh.getID() << " dest=" << destStoppingPlace->getID() << " sufficient space\n";
374 : }
375 : #endif
376 : }
377 :
378 : #ifdef DEBUG_STOPPINGPLACE
379 : if (DEBUGCOND) {
380 : std::cout << " stoppingPlaceResult=" << Named::getIDSecure(nearStoppingPlace) << "\n";
381 : }
382 : #endif
383 23359 : return nearStoppingPlace;
384 : }
385 :
386 :
387 : bool
388 23842 : MSStoppingPlaceRerouter::evaluateDestination(SUMOVehicle& veh, double brakeGap, bool newDestination, MSStoppingPlace* alternative,
389 : double occupancy, double prob, SUMOAbstractRouter<MSEdge, SUMOVehicle>& router, StoppingPlaceMap_t& stoppingPlaces,
390 : std::map<MSStoppingPlace*, ConstMSEdgeVector>& newRoutes, std::map<MSStoppingPlace*, ConstMSEdgeVector>& stoppingPlaceApproaches,
391 : StoppingPlaceParamMap_t& maxValues, StoppingPlaceParamMap_t& addInput) {
392 :
393 : // a map stores the stopping place values
394 : StoppingPlaceParamMap_t stoppingPlaceValues;
395 23842 : const SUMOTime now = SIMSTEP;
396 :
397 23842 : const MSRoute& route = veh.getRoute();
398 23842 : const RGBColor& c = route.getColor();
399 23842 : const MSEdge* stoppingPlaceEdge = &(alternative->getLane().getEdge());
400 :
401 23842 : const bool includeInternalLengths = MSGlobals::gUsingInternalLanes && MSNet::getInstance()->hasInternalLinks();
402 :
403 : // Compute the route from the current edge to the stopping place edge
404 : ConstMSEdgeVector edgesToStop;
405 23842 : const double targetPos = alternative->getLastFreePos(veh);
406 23842 : const MSEdge* rerouteOrigin = *veh.getRerouteOrigin();
407 23842 : router.compute(rerouteOrigin, veh.getPositionOnLane(), stoppingPlaceEdge, targetPos, &veh, now, edgesToStop, true);
408 :
409 23842 : if (edgesToStop.size() > 0) {
410 : // Compute the route from the stopping place edge to the end of the route
411 23370 : if (rerouteOrigin != veh.getEdge()) {
412 5 : edgesToStop.insert(edgesToStop.begin(), veh.getEdge());
413 : }
414 : ConstMSEdgeVector edgesFromStop;
415 23370 : stoppingPlaceApproaches[alternative] = edgesToStop;
416 :
417 23370 : const MSEdge* nextDestination = route.getLastEdge();
418 23370 : double nextPos = veh.getArrivalPos();
419 23370 : int nextDestinationIndex = route.size() - 1;
420 23370 : if (!newDestination) {
421 21954 : std::vector<std::pair<int, double> > stopIndices = veh.getStopIndices();
422 21954 : if (stopIndices.size() > 1) {
423 341 : nextDestinationIndex = stopIndices[1].first;
424 341 : nextDestination = route.getEdges()[nextDestinationIndex];
425 341 : nextPos = stopIndices[1].second;
426 :
427 : }
428 21954 : router.compute(stoppingPlaceEdge, targetPos, nextDestination, nextPos, &veh, now, edgesFromStop, true);
429 21954 : }
430 23370 : if (edgesFromStop.size() > 0 || newDestination) {
431 23370 : stoppingPlaceValues["probability"] = prob;
432 23370 : if (stoppingPlaceValues["probability"] > maxValues["probability"]) {
433 11703 : maxValues["probability"] = stoppingPlaceValues["probability"];
434 : }
435 23370 : stoppingPlaceValues["capacity"] = getStoppingPlaceCapacity(alternative);
436 23370 : stoppingPlaceValues["absfreespace"] = stoppingPlaceValues["capacity"] - occupancy;
437 : // if capacity = 0 then absfreespace and relfreespace are also 0
438 46612 : stoppingPlaceValues["relfreespace"] = stoppingPlaceValues["absfreespace"] / MAX2(1.0, stoppingPlaceValues["capacity"]);
439 23370 : MSRoute routeToPark(route.getID() + "!to" + myParamPrefix + "#1", edgesToStop, false,
440 46740 : &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), route.getStops());
441 :
442 : // The distance from the current edge to the new parking area
443 23370 : double toPos = alternative->getBeginLanePosition();
444 23370 : if (&alternative->getLane().getEdge() == veh.getEdge()) {
445 601 : toPos = MAX2(veh.getPositionOnLane(), toPos);
446 : }
447 23370 : stoppingPlaceValues["distanceto"] = routeToPark.getDistanceBetween(veh.getPositionOnLane(), toPos,
448 23370 : routeToPark.begin(), routeToPark.end() - 1, includeInternalLengths);
449 :
450 23370 : if (stoppingPlaceValues["distanceto"] == std::numeric_limits<double>::max()) {
451 0 : WRITE_WARNINGF(TL("Invalid distance computation for vehicle '%' to stopping place '%' at time=%."),
452 : veh.getID(), alternative->getID(), time2string(now));
453 : }
454 23370 : const double endPos = getStoppingPlaceOccupancy(alternative) == getStoppingPlaceCapacity(alternative)
455 23370 : ? alternative->getLastFreePos(veh, veh.getPositionOnLane() + brakeGap)
456 8626 : : alternative->getEndLanePosition();
457 23370 : const double distToEnd = stoppingPlaceValues["distanceto"] - toPos + endPos;
458 :
459 23370 : if (distToEnd < brakeGap) {
460 245 : rememberStoppingPlaceScore(veh, alternative, "tooClose");
461 245 : return false;
462 : }
463 :
464 : // The time to reach the new stopping place
465 23125 : stoppingPlaceValues["timeto"] = router.recomputeCosts(edgesToStop, &veh, SIMSTEP) - ((alternative->getLane().getLength() - alternative->getEndLanePosition()) / alternative->getLane().getSpeedLimit());
466 23125 : ConstMSEdgeVector newEdges = edgesToStop;
467 23125 : if (newDestination) {
468 1416 : stoppingPlaceValues["distancefrom"] = 0;
469 1416 : stoppingPlaceValues["timefrom"] = 0;
470 : } else {
471 21709 : MSRoute routeFromPark(route.getID() + "!from" + myParamPrefix + "#1", edgesFromStop, false,
472 43418 : &c == &RGBColor::DEFAULT_COLOR ? nullptr : new RGBColor(c), route.getStops());
473 : // The distance from the new parking area to the end of the route
474 21709 : stoppingPlaceValues["distancefrom"] = routeFromPark.getDistanceBetween(alternative->getBeginLanePosition(), routeFromPark.getLastEdge()->getLength(),
475 21709 : routeFromPark.begin(), routeFromPark.end() - 1, includeInternalLengths);
476 21709 : if (stoppingPlaceValues["distancefrom"] == std::numeric_limits<double>::max()) {
477 0 : WRITE_WARNINGF(TL("Invalid distance computation for vehicle '%' from stopping place '%' at time=%."),
478 : veh.getID(), alternative->getID(), time2string(SIMSTEP));
479 : }
480 : // The time to reach this area
481 21709 : stoppingPlaceValues["timefrom"] = router.recomputeCosts(edgesFromStop, &veh, SIMSTEP) - (alternative->getEndLanePosition() / alternative->getLane().getSpeedLimit());
482 21709 : newEdges.insert(newEdges.end(), edgesFromStop.begin() + 1, edgesFromStop.end());
483 21709 : newEdges.insert(newEdges.end(), route.begin() + nextDestinationIndex + 1, route.end());
484 21709 : }
485 :
486 : // add some additional/custom target function components
487 23125 : if (!evaluateCustomComponents(veh, brakeGap, newDestination, alternative, occupancy, prob, router, stoppingPlaceValues, stoppingPlaceApproaches[alternative], newEdges, maxValues, addInput)) {
488 : return false;
489 : }
490 23125 : if (!myCheckValidity || validComponentValues(stoppingPlaceValues)) {
491 23061 : updateMaxValues(stoppingPlaceValues, maxValues);
492 23061 : stoppingPlaces[alternative] = stoppingPlaceValues;
493 23061 : newRoutes[alternative] = newEdges;
494 : return true;
495 : } else {
496 : return false;
497 : }
498 23370 : } else {
499 0 : rememberStoppingPlaceScore(veh, alternative, "unreachable");
500 : }
501 23370 : } else {
502 944 : rememberStoppingPlaceScore(veh, alternative, "unreachable");
503 : }
504 : // unreachable
505 : return false;
506 23842 : }
507 :
508 :
509 : bool
510 22849 : MSStoppingPlaceRerouter::evaluateCustomComponents(SUMOVehicle& /*veh*/, double /*brakeGap*/, bool /*newDestination*/,
511 : MSStoppingPlace* /*alternative*/, double /*occupancy*/, double /*prob*/, SUMOAbstractRouter<MSEdge, SUMOVehicle>& /*router*/,
512 : StoppingPlaceParamMap_t& /*stoppingPlaceValues*/, ConstMSEdgeVector& /*newRoute*/, ConstMSEdgeVector& /*stoppingPlaceApproach*/,
513 : StoppingPlaceParamMap_t& /*maxValues*/, StoppingPlaceParamMap_t& /*addInput*/) {
514 22849 : return true;
515 : }
516 :
517 :
518 : bool
519 0 : MSStoppingPlaceRerouter::validComponentValues(StoppingPlaceParamMap_t& /* stoppingPlaceValues */) {
520 0 : return true;
521 : }
522 :
523 :
524 : bool
525 50783 : MSStoppingPlaceRerouter::useStoppingPlace(MSStoppingPlace* /* stoppingPlace */) {
526 50783 : return true;
527 : }
528 :
529 :
530 : SUMOAbstractRouter<MSEdge, SUMOVehicle>&
531 24346 : MSStoppingPlaceRerouter::getRouter(SUMOVehicle& veh, const MSEdgeVector& prohibited) {
532 24346 : return MSNet::getInstance()->getRouterTT(veh.getRNGIndex(), prohibited);
533 : }
534 :
535 :
536 : MSStoppingPlaceRerouter::StoppingPlaceParamMap_t
537 12243 : MSStoppingPlaceRerouter::collectWeights(SUMOVehicle& veh) {
538 : MSStoppingPlaceRerouter::StoppingPlaceParamMap_t result;
539 12243 : myEvalParams["distanceto"] = getWeight(veh, "distance.weight", myEvalParams["distanceto"]);
540 110307 : for (auto evalParam : myEvalParams) {
541 98064 : result[evalParam.first] = getWeight(veh, evalParam.first + ".weight", evalParam.second);
542 : }
543 12243 : result["probability"] = getWeight(veh, "probability.weight", 0.);
544 12243 : return result;
545 : }
546 :
547 :
548 : double
549 221139 : MSStoppingPlaceRerouter::getWeight(SUMOVehicle& veh, const std::string param, const double defaultWeight, const bool warn) {
550 : // get custom vehicle parameter
551 221139 : const std::string key = myParamPrefix + "." + param;
552 221139 : if (veh.getParameter().hasParameter(key)) {
553 : try {
554 88 : return StringUtils::toDouble(veh.getParameter().getParameter(key, "-1"));
555 0 : } catch (...) {
556 0 : WRITE_WARNINGF(TL("Invalid value '%' for vehicle parameter '%'"), veh.getParameter().getParameter(key, "-1"), key);
557 0 : }
558 : } else {
559 : // get custom vType parameter
560 221095 : if (veh.getVehicleType().getParameter().hasParameter(key)) {
561 : try {
562 31828 : return StringUtils::toDouble(veh.getVehicleType().getParameter().getParameter(key, "-1"));
563 0 : } catch (...) {
564 0 : WRITE_WARNINGF(TL("Invalid value '%' for vType parameter '%'"), veh.getVehicleType().getParameter().getParameter(key, "-1"), key);
565 0 : }
566 : }
567 : }
568 205181 : if (warn) {
569 0 : WRITE_MESSAGEF("Vehicle '%' does not supply vehicle parameter '%'. Using default of %\n", veh.getID(), key, toString(defaultWeight));
570 : }
571 205181 : return defaultWeight;
572 : }
573 :
574 :
575 : void
576 23061 : MSStoppingPlaceRerouter::updateMaxValues(StoppingPlaceParamMap_t& stoppingPlaceValues, StoppingPlaceParamMap_t& maxValues) {
577 207973 : for (auto it = maxValues.begin(); it != maxValues.end(); ++it) {
578 184912 : if (stoppingPlaceValues[it->first] > it->second) {
579 108593 : it->second = stoppingPlaceValues[it->first];
580 : }
581 : }
582 23061 : }
583 :
584 :
585 : double
586 23041 : MSStoppingPlaceRerouter::getTargetValue(const StoppingPlaceParamMap_t& absValues, const StoppingPlaceParamMap_t& maxValues, const StoppingPlaceParamMap_t& weights, const StoppingPlaceParamSwitchMap_t& norm, const StoppingPlaceParamSwitchMap_t& invert) {
587 : double cost = 0.;
588 207793 : for (StoppingPlaceParamMap_t::const_iterator sc = absValues.begin(); sc != absValues.end(); ++sc) {
589 184752 : double weight = weights.at(sc->first);
590 184752 : double val = sc->second;
591 184752 : if (norm.at(sc->first) && maxValues.at(sc->first) > 0.) {
592 158535 : val /= maxValues.at(sc->first);
593 : }
594 184752 : cost += (invert.at(sc->first)) ? weight * (1. - val) : weight * val;
595 : }
596 23041 : return cost;
597 : }
598 :
599 :
600 : /****************************************************************************/
|