LCOV - code coverage report
Current view: top level - src/microsim/trigger - MSStoppingPlaceRerouter.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 91.8 % 257 236
Test Date: 2026-03-02 16:00:03 Functions: 91.7 % 12 11

            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              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1