LCOV - code coverage report
Current view: top level - src/microsim/devices - MSRoutingEngine.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 92.1 % 403 371
Test Date: 2026-09-23 15:43:02 Functions: 100.0 % 30 30

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2007-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    MSRoutingEngine.cpp
      15              : /// @author  Michael Behrisch
      16              : /// @author  Daniel Krajzewicz
      17              : /// @author  Laura Bieker
      18              : /// @author  Christoph Sommer
      19              : /// @author  Jakob Erdmann
      20              : /// @date    Tue, 04 Dec 2007
      21              : ///
      22              : // A device that performs vehicle rerouting based on current edge speeds
      23              : /****************************************************************************/
      24              : #include <config.h>
      25              : 
      26              : #include "MSRoutingEngine.h"
      27              : #include <microsim/MSNet.h>
      28              : #include <microsim/MSLane.h>
      29              : #include <microsim/MSJunction.h>
      30              : #include <microsim/MSEdge.h>
      31              : #include <microsim/MSEdgeControl.h>
      32              : #include <microsim/MSEventControl.h>
      33              : #include <microsim/MSGlobals.h>
      34              : #include <microsim/MSVehicleControl.h>
      35              : #include <microsim/MSVehicleType.h>
      36              : #include <microsim/MSVehicle.h>
      37              : #include <microsim/MSRoute.h>
      38              : #include <microsim/MSEdgeWeightsStorage.h>
      39              : #include <mesosim/MEVehicle.h>
      40              : #include <libsumo/TraCIConstants.h>
      41              : #include <utils/vehicle/SUMOVehicleParameter.h>
      42              : #include <set>
      43              : #include <microsim/MSInsertionControl.h>
      44              : #include <microsim/transportables/MSTransportable.h>
      45              : #include <microsim/devices/MSDevice_Taxi.h>
      46              : #include <utils/options/OptionsCont.h>
      47              : #include <utils/common/WrappingCommand.h>
      48              : #include <utils/common/StaticCommand.h>
      49              : #include <utils/common/StringUtils.h>
      50              : #include <utils/xml/SUMOSAXAttributes.h>
      51              : #include <utils/router/DijkstraRouter.h>
      52              : #include <utils/router/AStarRouter.h>
      53              : #include <utils/router/CHRouter.h>
      54              : #include <utils/router/CHRouterWrapper.h>
      55              : #include <utils/vehicle/SUMOVehicleParserHelper.h>
      56              : #include <utils/router/CCHGraph.h>
      57              : #include <utils/router/CCHMetricFamily.h>
      58              : #include <utils/router/CCHRouter.h>
      59              : #pragma GCC diagnostic push
      60              : #pragma GCC diagnostic ignored "-Wunused-parameter"
      61              : #include <routingkit/customizable_contraction_hierarchy.h>
      62              : #pragma GCC diagnostic pop
      63              : 
      64              : //#define DEBUG_SEPARATE_TURNS
      65              : #define DEBUG_COND(obj) (obj->isSelected())
      66              : 
      67              : // ===========================================================================
      68              : // static member variables
      69              : // ===========================================================================
      70              : std::vector<double> MSRoutingEngine::myEdgeSpeeds;
      71              : std::vector<double> MSRoutingEngine::myEdgeBikeSpeeds;
      72              : std::vector<MSRoutingEngine::TimeAndCount> MSRoutingEngine::myEdgeTravelTimes;
      73              : std::vector<std::vector<double> > MSRoutingEngine::myPastEdgeSpeeds;
      74              : std::vector<std::vector<double> > MSRoutingEngine::myPastEdgeBikeSpeeds;
      75              : Command* MSRoutingEngine::myEdgeWeightSettingCommand = nullptr;
      76              : double MSRoutingEngine::myAdaptationWeight(0);
      77              : int MSRoutingEngine::myAdaptationSteps;
      78              : int MSRoutingEngine::myAdaptationStepsIndex = 0;
      79              : SUMOTime MSRoutingEngine::myAdaptationInterval = -1;
      80              : SUMOTime MSRoutingEngine::myLastAdaptation = -1;
      81              : bool MSRoutingEngine::myWithTaz;
      82              : bool MSRoutingEngine::myBikeSpeeds;
      83              : MSRouterProvider* MSRoutingEngine::myRouterProvider = nullptr;
      84              : std::map<std::pair<const MSEdge*, const MSEdge*>, ConstMSRoutePtr> MSRoutingEngine::myCachedRoutes;
      85              : double MSRoutingEngine::myPriorityFactor(0);
      86              : double MSRoutingEngine::myMinEdgePriority(std::numeric_limits<double>::max());
      87              : double MSRoutingEngine::myEdgePriorityRange(0);
      88              : bool MSRoutingEngine::myDynamicRandomness(false);
      89              : bool MSRoutingEngine::myHaveExtras(false);
      90              : 
      91              : SUMOAbstractRouter<MSEdge, SUMOVehicle>::Operation MSRoutingEngine::myEffortFunc = &MSRoutingEngine::getEffort;
      92              : #ifdef HAVE_FOX
      93              : FXMutex MSRoutingEngine::myRouteCacheMutex;
      94              : #endif
      95              : MSCCHGraph* MSRoutingEngine::myCCHGraph = nullptr;
      96              : MSCCHMetricFamily* MSRoutingEngine::myCCHLive = nullptr;
      97              : MSCCHMetricFamily* MSRoutingEngine::myCCHFreeflow = nullptr;
      98              : 
      99              : 
     100              : // ===========================================================================
     101              : // method definitions
     102              : // ===========================================================================
     103              : void
     104      1413745 : MSRoutingEngine::initWeightUpdate(SUMOTime lastAdaptation) {
     105      1413745 :     if (myAdaptationInterval == -1) {
     106         8397 :         myEdgeWeightSettingCommand = nullptr;
     107         8397 :         myLastAdaptation = lastAdaptation;
     108         8397 :         const OptionsCont& oc = OptionsCont::getOptions();
     109         8397 :         myWithTaz = oc.getBool("device.rerouting.with-taz");
     110         8397 :         myAdaptationInterval = string2time(oc.getString("device.rerouting.adaptation-interval"));
     111         8397 :         myAdaptationWeight = oc.getFloat("device.rerouting.adaptation-weight");
     112         8397 :         const SUMOTime period = string2time(oc.getString("device.rerouting.period"));
     113         8397 :         if (myAdaptationWeight < 1. && myAdaptationInterval > 0) {
     114              :             SUMOTime nextAdaptation = -1;
     115         8323 :             if (lastAdaptation >= 0) {
     116            5 :                 nextAdaptation = lastAdaptation + myAdaptationInterval;
     117              :             }
     118         8323 :             myEdgeWeightSettingCommand = new StaticCommand<MSRoutingEngine>(&MSRoutingEngine::adaptEdgeEfforts);
     119         8323 :             MSNet::getInstance()->getEndOfTimestepEvents()->addEvent(myEdgeWeightSettingCommand, nextAdaptation);
     120         8397 :         } else if (period > 0) {
     121            0 :             WRITE_WARNING(TL("Rerouting is useless if the edge weights do not get updated!"));
     122              :         }
     123        16794 :         OutputDevice::createDeviceByOption("device.rerouting.output", "weights", "meandata_file.xsd");
     124              :     }
     125      1413745 : }
     126              : 
     127              : 
     128              : void
     129     89178868 : MSRoutingEngine::initEdgeWeights(SUMOVehicleClass svc, SUMOTime lastAdaption, int index) {
     130     89178868 :     const OptionsCont& oc = OptionsCont::getOptions();
     131     89202184 :     if (myAdaptationWeight == 0 || !oc.isDefault("device.rerouting.adaptation-steps")) {
     132     89155552 :         myAdaptationSteps = oc.getInt("device.rerouting.adaptation-steps");
     133              :     }
     134     89178868 :     if (myBikeSpeeds && svc == SVC_BICYCLE) {
     135          336 :         _initEdgeWeights(myEdgeBikeSpeeds, myPastEdgeBikeSpeeds);
     136              :     } else {
     137     89178532 :         _initEdgeWeights(myEdgeSpeeds, myPastEdgeSpeeds);
     138              :     }
     139     89178868 :     if (lastAdaption >= 0) {
     140          186 :         myLastAdaptation = lastAdaption;
     141              :     }
     142     89178868 :     if (index >= 0 && myAdaptationSteps > 0) {
     143              :         assert(index < myAdaptationSteps);
     144          186 :         myAdaptationStepsIndex = index;
     145              :     }
     146     89178868 : }
     147              : 
     148              : 
     149              : void
     150        42187 : MSRoutingEngine::initWeightConstants(const OptionsCont& oc) {
     151        84374 :     if (oc.getFloat("weights.priority-factor") != 0) {
     152           40 :         myPriorityFactor = oc.getFloat("weights.priority-factor");
     153           40 :         if (myPriorityFactor < 0) {
     154            0 :             throw ProcessError(TL("weights.priority-factor cannot be negative."));
     155              :         }
     156           40 :         myMinEdgePriority = std::numeric_limits<double>::max();
     157              :         double maxEdgePriority = -std::numeric_limits<double>::max();
     158          416 :         for (const MSEdge* const edge : MSNet::getInstance()->getEdgeControl().getEdges()) {
     159          376 :             maxEdgePriority = MAX2(maxEdgePriority, (double)edge->getPriority());
     160          632 :             myMinEdgePriority = MIN2(myMinEdgePriority, (double)edge->getPriority());
     161              :         }
     162           40 :         myEdgePriorityRange = maxEdgePriority - myMinEdgePriority;
     163           40 :         if (myEdgePriorityRange == 0) {
     164            0 :             WRITE_WARNING(TL("Option weights.priority-factor does not take effect because all edges have the same priority"));
     165            0 :             myPriorityFactor = 0;
     166              :         }
     167              :     }
     168        42187 :     myDynamicRandomness = oc.getBool("weights.random-factor.dynamic");
     169        42187 :     myHaveExtras = gRoutingPreferences || myPriorityFactor != 0 || gWeightsRandomFactor != 1;
     170        42187 : }
     171              : 
     172              : 
     173              : void
     174     89178868 : MSRoutingEngine::_initEdgeWeights(std::vector<double>& edgeSpeeds, std::vector<std::vector<double> >& pastEdgeSpeeds) {
     175     89178868 :     if (edgeSpeeds.empty()) {
     176         8310 :         const OptionsCont& oc = OptionsCont::getOptions();
     177         8310 :         const bool useLoaded = oc.getBool("device.rerouting.init-with-loaded-weights");
     178         8310 :         const double currentSecond = SIMTIME;
     179       813125 :         for (const MSEdge* const edge : MSNet::getInstance()->getEdgeControl().getEdges()) {
     180      1609630 :             while (edge->getNumericalID() >= (int)edgeSpeeds.size()) {
     181       804815 :                 edgeSpeeds.push_back(0);
     182       804815 :                 if (myAdaptationSteps > 0) {
     183       804037 :                     pastEdgeSpeeds.push_back(std::vector<double>());
     184              :                 }
     185       806695 :                 if (MSGlobals::gWeightsSeparateTurns && edgeSpeeds == myEdgeSpeeds) {
     186         1880 :                     myEdgeTravelTimes.push_back(TimeAndCount(0, 0));
     187              :                 }
     188              :             }
     189       804815 :             if (useLoaded) {
     190          124 :                 edgeSpeeds[edge->getNumericalID()] = edge->getLength() / MSNet::getTravelTime(edge, nullptr, currentSecond);
     191              :             } else {
     192       804691 :                 edgeSpeeds[edge->getNumericalID()] = edge->getMeanSpeed();
     193              :             }
     194       804815 :             if (myAdaptationSteps > 0) {
     195       804037 :                 pastEdgeSpeeds[edge->getNumericalID()] = std::vector<double>(myAdaptationSteps, edgeSpeeds[edge->getNumericalID()]);
     196              :             }
     197              :         }
     198         8310 :         myLastAdaptation = MSNet::getInstance()->getCurrentTimeStep();
     199              :     }
     200     89178868 : }
     201              : 
     202              : 
     203              : double
     204    254099594 : MSRoutingEngine::getEffort(const MSEdge* const e, const SUMOVehicle* const v, double) {
     205              :     const int id = e->getNumericalID();
     206    254099594 :     if (id < (int)myEdgeSpeeds.size()) {
     207    246244873 :         return MAX2(e->getLength() / MAX2(myEdgeSpeeds[id], NUMERICAL_EPS), e->getMinimumTravelTime(v));
     208              :     }
     209      7931638 :     return e->getMinimumTravelTime(v);
     210              : }
     211              : 
     212              : 
     213              : double
     214         3680 : MSRoutingEngine::getEffortBike(const MSEdge* const e, const SUMOVehicle* const v, double) {
     215              :     const int id = e->getNumericalID();
     216         3680 :     if (id < (int)myEdgeBikeSpeeds.size()) {
     217         3666 :         return MAX2(e->getLength() / MAX2(myEdgeBikeSpeeds[id], NUMERICAL_EPS), e->getMinimumTravelTime(v));
     218              :     }
     219           14 :     return e->getMinimumTravelTime(v);
     220              : }
     221              : 
     222              : 
     223              : double
     224       126692 : MSRoutingEngine::getEffortExtra(const MSEdge* const e, const SUMOVehicle* const v, double t) {
     225         6371 :     double effort = (!myBikeSpeeds || v == nullptr || v->getVClass() != SVC_BICYCLE
     226       131175 :                      ? getEffort(e, v, t)
     227         1888 :                      : getEffortBike(e, v, t));
     228       126692 :     applyExtras(e, v, SIMSTEP, effort);
     229       126692 :     return effort;
     230              : }
     231              : 
     232              : 
     233              : double
     234         4240 : MSRoutingEngine::getAssumedSpeed(const MSEdge* edge, const SUMOVehicle* veh) {
     235         4240 :     return edge->getLength() / myEffortFunc(edge, veh, 0);
     236              : }
     237              : 
     238              : 
     239              : SUMOTime
     240     86900952 : MSRoutingEngine::adaptEdgeEfforts(SUMOTime currentTime) {
     241     86900952 :     initEdgeWeights(SVC_PASSENGER);
     242     86900952 :     if (myBikeSpeeds) {
     243          256 :         initEdgeWeights(SVC_BICYCLE);
     244              :     }
     245     86900952 :     if (MSNet::getInstance()->getVehicleControl().getDepartedVehicleNo() == 0) {
     246     72517504 :         return myAdaptationInterval;
     247              :     }
     248              :     {
     249              : #ifdef HAVE_FOX
     250              :         FXMutexLock lock(myRouteCacheMutex);
     251              : #endif
     252              :         myCachedRoutes.clear();
     253              :     }
     254     14383448 :     const MSEdgeVector& edges = MSNet::getInstance()->getEdgeControl().getEdges();
     255     14383448 :     const double newWeightFactor = (double)(1. - myAdaptationWeight);
     256              :     bool cchEdgeMoved = false;
     257    847510865 :     for (const MSEdge* const e : edges) {
     258      8744922 :         if (e->isDelayed()) {
     259              :             const int id = e->getNumericalID();
     260    202223506 :             double currSpeed = e->getMeanSpeed();
     261    202223506 :             if (MSGlobals::gWeightsSeparateTurns > 0 && e->getNumSuccessors() > 1) {
     262       194890 :                 currSpeed = patchSpeedForTurns(e, currSpeed);
     263              :             }
     264              : #ifdef DEBUG_SEPARATE_TURNS
     265              :             if (DEBUG_COND(e->getLanes()[0])) {
     266              :                 std::cout << SIMTIME << " edge=" << e->getID()
     267              :                           << " meanSpeed=" << e->getMeanSpeed()
     268              :                           << " currSpeed=" << currSpeed
     269              :                           << " oldestSpeed=" << myPastEdgeSpeeds[id][myAdaptationStepsIndex]
     270              :                           << " oldAvg=" << myEdgeSpeeds[id]
     271              :                           << "\n";
     272              :             }
     273              : #endif
     274    202223506 :             const double oldSmoothedSpeed = myEdgeSpeeds[id];
     275    202223506 :             if (myAdaptationSteps > 0) {
     276              :                 // moving average
     277    202152032 :                 myEdgeSpeeds[id] += (currSpeed - myPastEdgeSpeeds[id][myAdaptationStepsIndex]) / myAdaptationSteps;
     278    202152032 :                 myPastEdgeSpeeds[id][myAdaptationStepsIndex] = currSpeed;
     279    202152032 :                 if (myBikeSpeeds) {
     280            0 :                     const double currBikeSpeed = e->getMeanSpeedBike();
     281            0 :                     myEdgeBikeSpeeds[id] += (currBikeSpeed - myPastEdgeBikeSpeeds[id][myAdaptationStepsIndex]) / myAdaptationSteps;
     282            0 :                     myPastEdgeBikeSpeeds[id][myAdaptationStepsIndex] = currBikeSpeed;
     283              :                 }
     284              :             } else {
     285              :                 // exponential moving average
     286        71474 :                 if (currSpeed != myEdgeSpeeds[id]) {
     287        27754 :                     myEdgeSpeeds[id] = myEdgeSpeeds[id] * myAdaptationWeight + currSpeed * newWeightFactor;
     288              :                 }
     289        71474 :                 if (myBikeSpeeds) {
     290         1454 :                     const double currBikeSpeed = e->getMeanSpeedBike();
     291         1454 :                     if (currBikeSpeed != myEdgeBikeSpeeds[id]) {
     292          902 :                         myEdgeBikeSpeeds[id] = myEdgeBikeSpeeds[id] * myAdaptationWeight + currBikeSpeed * newWeightFactor;
     293              :                     }
     294              :                 }
     295              :             }
     296              :             // sparse CCH re-customization: remember which edges actually
     297              :             // moved; the update deadband is applied at the customize barrier
     298    202223506 :             if (myCCHLive != nullptr && myEdgeSpeeds[id] != oldSmoothedSpeed) {
     299      1115388 :                 myCCHLive->markDirty(e);
     300              :                 cchEdgeMoved = true;
     301              :             }
     302              :         }
     303              :     }
     304     14383448 :     if (myAdaptationSteps > 0) {
     305     14361336 :         myAdaptationStepsIndex = (myAdaptationStepsIndex + 1) % myAdaptationSteps;
     306              :     }
     307     14383448 :     myLastAdaptation = currentTime;
     308              :     // The device's CCH customization barrier: re-customize the metrics from
     309              :     // the freshly updated speed tables and publish (double-buffered). Runs
     310              :     // on the main thread after the speed update; no worker query is in
     311              :     // flight at this point. The family skips quiet barriers and runs that
     312              :     // never route (see CCHMetricFamily::atBarrier: measured on Lausanne, the
     313              :     // unconditional per-tick customize was 80% of meso wall time at
     314              :     // adaptation-interval 2, and ran even with rerouting probability 0).
     315     14383448 :     if (myCCHLive != nullptr) {
     316       287654 :         myCCHLive->atBarrier(STEPS2TIME(currentTime), cchEdgeMoved);
     317              :     }
     318     28766896 :     if (OptionsCont::getOptions().isSet("device.rerouting.output")) {
     319        13568 :         OutputDevice& dev = OutputDevice::getDeviceByOption("device.rerouting.output");
     320        13568 :         dev.openTag(SUMO_TAG_INTERVAL);
     321        13568 :         dev.writeAttr(SUMO_ATTR_ID, "device.rerouting");
     322        13568 :         dev.writeAttr(SUMO_ATTR_BEGIN, STEPS2TIME(currentTime));
     323        13568 :         dev.writeAttr(SUMO_ATTR_END, STEPS2TIME(currentTime + myAdaptationInterval));
     324       162963 :         for (const MSEdge* e : edges) {
     325       149395 :             dev.openTag(SUMO_TAG_EDGE);
     326       149395 :             dev.writeAttr(SUMO_ATTR_ID, e->getID());
     327       149395 :             dev.writeAttr("traveltime", myEffortFunc(e, nullptr, STEPS2TIME(currentTime)));
     328       149395 :             if (myBikeSpeeds) {
     329              :                 // @note edge-priority is not included here
     330         1792 :                 dev.writeAttr("traveltimeBike", getEffortBike(e, nullptr, STEPS2TIME(currentTime)));
     331              :             }
     332       298790 :             dev.closeTag();
     333              :         }
     334        27136 :         dev.closeTag();
     335              :     }
     336     14383448 :     return myAdaptationInterval;
     337              : }
     338              : 
     339              : 
     340              : MSCCHGraph*
     341          427 : MSRoutingEngine::ensureCCHGraph() {
     342          427 :     if (myCCHGraph == nullptr) {
     343          302 :         myCCHGraph = new MSCCHGraph(MSEdge::getAllEdges());  // union topology; class masks prime at first fill
     344              :     }
     345          427 :     return myCCHGraph;
     346              : }
     347              : 
     348              : 
     349              : void
     350          229 : MSRoutingEngine::initCCH() {
     351          229 :     if (myCCHLive != nullptr) {
     352            0 :         return;  // device-side state built once (the graph alone may already
     353              :         // exist for MSNet's free-flow router)
     354              :     }
     355              :     // One LIVE metric per vehicle TYPE known when routing starts (see
     356              :     // utils/router/CCHMetricFamily.h for the keying and buffer semantics).
     357              :     // All types share ONE CCH topology (the union); route files stream, so
     358              :     // types appearing later register through the family's wanted list and
     359              :     // get their metric at the next customization barrier.
     360          229 :     ensureCCHGraph();
     361          229 :     const OptionsCont& oc = OptionsCont::getOptions();
     362          229 :     myCCHLive = new MSCCHMetricFamily(
     363              :         myCCHGraph, myEffortFunc, &MSRoutingEngine::getEffort,
     364              :         oc.getFloat("device.rerouting.cch-update-threshold.factor"),
     365          458 :         STEPS2TIME(string2time(oc.getString("device.rerouting.cch-update-threshold.constant"))),
     366              :         &MSRoutingEngine::buildCCHRefVehicle,
     367          916 :         oc.getInt("device.rerouting.cch-ensemble"));
     368              :     std::vector<std::string> vtypeIDs;
     369          229 :     MSNet::getInstance()->getVehicleControl().insertVTypeIDs(vtypeIDs);
     370         1678 :     for (const std::string& id : vtypeIDs) {
     371         1449 :         const MSVehicleType* vt = MSNet::getInstance()->getVehicleControl().getVType(id, nullptr, true);
     372         1449 :         if (vt != nullptr && !vt->isVehicleSpecific()) {
     373         1449 :             myCCHLive->seedKey(vt);
     374              :         }
     375              :     }
     376              :     // publish initial metrics so the first queries succeed
     377          229 :     myCCHLive->customize(STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep()));
     378          229 : }
     379              : 
     380              : 
     381              : SUMOVehicle*
     382         1543 : MSRoutingEngine::buildCCHRefVehicle(const MSVehicleType* type, int slot) {
     383              :     // The effort-reference vehicle: constructed DIRECTLY (what buildVehicle
     384              :     // does minus initVehicle), so it is never counted in the vehicle
     385              :     // statistics, never given devices and never inserted -- it exists only
     386              :     // so every metric fill evaluates the same reference. The mean speed
     387              :     // factor makes it deterministic (the findRoute precedent) and the fixed
     388              :     // id makes the frozen weights.random-factor realization reproducible
     389              :     // (the random seed is a hash of the id).
     390         1543 :     SUMOVehicleParameter* pars = new SUMOVehicleParameter();
     391              :     // slot 0 keeps the historical id (and with it the frozen random-factor
     392              :     // realization); ensemble slots differ only in the id, which seeds their
     393              :     // own realization -- see CCHMetricFamily::RefVehicleFactory
     394         3086 :     pars->id = "cchRef:" + type->getID() + (slot == 0 ? "" : ":" + toString(slot));
     395              :     const MSEdge* refEdge = nullptr;
     396       132724 :     for (const MSEdge* e : MSEdge::getAllEdges()) {
     397       132724 :         if (!e->isInternal() && !e->isTazConnector()) {
     398              :             refEdge = e;
     399              :             break;
     400              :         }
     401              :     }
     402         3086 :     ConstMSRoutePtr route = std::make_shared<MSRoute>(pars->id, ConstMSEdgeVector({refEdge}), false, nullptr, StopParVector());
     403         1543 :     if (MSGlobals::gUseMesoSim) {
     404              :         return new MEVehicle(pars, route, const_cast<MSVehicleType*>(type),
     405            3 :                              type->getSpeedFactor().getParameter(0));
     406              :     }
     407              :     return new MSVehicle(pars, route, const_cast<MSVehicleType*>(type),
     408         4626 :                          type->getSpeedFactor().getParameter(0));
     409              : }
     410              : 
     411              : 
     412              : void
     413         1416 : MSRoutingEngine::invalidateCCHEdge(const MSEdge* e) {
     414         1416 :     if (myCCHGraph == nullptr) {
     415              :         return;
     416              :     }
     417              :     // the primed connection masks reflect the OLD successor lists; the next
     418              :     // fill of either family re-primes from the live ones. Safe to do right
     419              :     // here: masks are only read at fill time, and every fill runs on the
     420              :     // main thread (the device barrier, the free-flow repair) -- never on a
     421              :     // query thread.
     422              :     myCCHGraph->invalidateClassMasks();
     423           43 :     if (myCCHFreeflow != nullptr) {
     424              :         myCCHFreeflow->flagPermissionsStale();
     425              :     }
     426           43 :     if (myCCHLive != nullptr) {
     427           20 :         myCCHLive->invalidateEdge(e);
     428              :     }
     429              : }
     430              : 
     431              : 
     432              : const RoutingKit::CustomizableContractionHierarchyMetric*
     433        58836 : MSRoutingEngine::getPublishedCCHMetric(SUMOVehicleClass /* vClass */, SUMOTime /* time */, const SUMOVehicle* veh) {
     434              :     // the published metrics always track the live speeds; the query time
     435              :     // only matters for duarouter's per-weight-period metrics. Lookup is by
     436              :     // vehicle TYPE (the metric's exactness key); a vehicle-specific type
     437              :     // (TraCI-modified singular copy) routes on the exact fallback rather
     438              :     // than on another type's metric.
     439        58836 :     if (veh == nullptr || myCCHLive == nullptr) {
     440              :         return nullptr;
     441              :     }
     442        58836 :     const MSVehicleType* type = &veh->getVehicleType();
     443        58836 :     if (type->isVehicleSpecific()) {
     444              :         return nullptr;
     445              :     }
     446        58836 :     return myCCHLive->published(type, veh->getID());
     447              : }
     448              : 
     449              : 
     450              : const RoutingKit::CustomizableContractionHierarchyMetric*
     451        16418 : MSRoutingEngine::getFreeflowCCHMetric(SUMOVehicleClass /* vClass */, SUMOTime /* time */, const SUMOVehicle* veh) {
     452              :     // MAIN-THREAD ONLY (see header): MSNet's routers serve TraCI, triggers
     453              :     // and the GUI, never the rerouting worker threads, so the family's lazy
     454              :     // creation and stale repair may run synchronously right here.
     455        16418 :     if (veh == nullptr) {
     456              :         return nullptr;
     457              :     }
     458              :     // Everything MSNet::getTravelTime reads ahead of the free-flow layer is
     459              :     // per-vehicle and cannot live in a shared metric -> exact fallback:
     460              :     // individual TraCI edge weights, global TraCI edge weights, a routing
     461              :     // mode other than DEFAULT (the AGGREGATED modes belong to the device
     462              :     // metrics; the transient-permission modes already fall back inside
     463              :     // CCHRouter::compute).
     464        16418 :     if (veh->getRoutingMode() != libsumo::ROUTING_MODE_DEFAULT
     465        16418 :             || !MSNet::getInstance()->getWeightsStorage().empty()) {
     466            0 :         return nullptr;
     467              :     }
     468        16418 :     const MSVehicle* const msVeh = dynamic_cast<const MSVehicle*>(veh);
     469        16418 :     if (msVeh != nullptr && !msVeh->getWeightsStorage().empty()) {
     470              :         return nullptr;
     471              :     }
     472        16418 :     const MSVehicleType* type = &veh->getVehicleType();
     473        16418 :     if (type->isVehicleSpecific()) {
     474              :         return nullptr;
     475              :     }
     476        16418 :     if (myCCHFreeflow == nullptr) {
     477              :         // free-flow efforts are static: a STATIC family with a single weight
     478              :         // period, lazily customized per type on first query
     479           91 :         myCCHFreeflow = new MSCCHMetricFamily(
     480           91 :             ensureCCHGraph(), &MSNet::getTravelTime, 0, SUMOTime_MAX,
     481          182 :             &MSRoutingEngine::buildCCHRefVehicle, nullptr);
     482              :     }
     483        16418 :     return myCCHFreeflow->get(type, type->getVehicleClass(),
     484        16418 :                               MSNet::getInstance()->getCurrentTimeStep(), veh);
     485              : }
     486              : 
     487              : 
     488              : double
     489       194890 : MSRoutingEngine::patchSpeedForTurns(const MSEdge* edge, double currSpeed) {
     490              :     const double length = edge->getLength();
     491              :     double maxSpeed = 0;
     492       840432 :     for (const auto& pair : edge->getViaSuccessors()) {
     493       645542 :         if (pair.second == nullptr) {
     494        63678 :             continue;
     495              :         }
     496       581864 :         TimeAndCount& tc = myEdgeTravelTimes[pair.second->getNumericalID()];
     497       581864 :         if (tc.second > 0) {
     498        69261 :             const double avgSpeed = length / STEPS2TIME(tc.first / tc.second);
     499              :             maxSpeed = MAX2(avgSpeed, maxSpeed);
     500              :         }
     501              :     }
     502       194890 :     if (maxSpeed > 0) {
     503              :         // perform correction
     504        44133 :         const double correctedSpeed = MSGlobals::gWeightsSeparateTurns * maxSpeed + (1 - MSGlobals::gWeightsSeparateTurns) * currSpeed;
     505       197740 :         for (const auto& pair : edge->getViaSuccessors()) {
     506       153607 :             if (pair.second == nullptr) {
     507        15453 :                 continue;
     508              :             }
     509              :             const int iid = pair.second->getNumericalID();
     510       138154 :             TimeAndCount& tc = myEdgeTravelTimes[iid];
     511       138154 :             if (tc.second > 0) {
     512        69261 :                 const double avgSpeed = length / STEPS2TIME(tc.first / tc.second);
     513        69261 :                 if (avgSpeed < correctedSpeed) {
     514        26911 :                     double internalTT = pair.second->getLength() / pair.second->getSpeedLimit();
     515        26911 :                     internalTT += (length / avgSpeed - length / correctedSpeed) * MSGlobals::gWeightsSeparateTurns;
     516        26911 :                     const double origInternalSpeed = myEdgeSpeeds[iid];
     517        26911 :                     const double newInternalSpeed = pair.second->getLength() / internalTT;
     518        26911 :                     const double origCurrSpeed = myPastEdgeSpeeds[iid][myAdaptationStepsIndex];
     519              : 
     520        26911 :                     myEdgeSpeeds[iid] = newInternalSpeed;
     521              :                     // to ensure myEdgeSpeed reverts to the speed limit
     522              :                     // when there are no updates, we also have to patch
     523              :                     // myPastEdgeSpeeds with a virtual value that is consistent
     524              :                     // with the updated speed
     525              :                     // note: internal edges were handled before the normal ones
     526        26911 :                     const double virtualSpeed = (newInternalSpeed - (origInternalSpeed - origCurrSpeed / myAdaptationSteps)) * myAdaptationSteps;
     527        26911 :                     myPastEdgeSpeeds[iid][myAdaptationStepsIndex] = virtualSpeed;
     528              : 
     529              : #ifdef DEBUG_SEPARATE_TURNS
     530              :                     if (DEBUG_COND(pair.second->getLanes()[0])) {
     531              :                         std::cout << SIMTIME << " edge=" << edge->getID() << " to=" << pair.first->getID() << " via=" << pair.second->getID()
     532              :                                   << " origSpeed=" << currSpeed
     533              :                                   << " maxSpeed=" << maxSpeed
     534              :                                   << " correctedSpeed=" << correctedSpeed
     535              :                                   << " avgSpeed=" << avgSpeed
     536              :                                   << " internalTT=" << internalTT
     537              :                                   << " internalSpeed=" << origInternalSpeed
     538              :                                   << " newInternalSpeed=" << newInternalSpeed
     539              :                                   << " virtualSpeed=" << virtualSpeed
     540              :                                   << "\n";
     541              :                     }
     542              : #endif
     543              :                 }
     544        69261 :                 if (myAdaptationStepsIndex == 0) {
     545          738 :                     tc.first = 0;
     546          738 :                     tc.second = 0;
     547              :                 }
     548              :             }
     549              :         }
     550              :         return correctedSpeed;
     551              :     }
     552              :     return currSpeed;
     553              : }
     554              : 
     555              : 
     556              : ConstMSRoutePtr
     557       465910 : MSRoutingEngine::getCachedRoute(const std::pair<const MSEdge*, const MSEdge*>& key) {
     558              : #ifdef HAVE_FOX
     559              :     // worker threads insert into the cache concurrently (RoutingTask::run)
     560              :     FXMutexLock lock(myRouteCacheMutex);
     561              : #endif
     562              :     auto routeIt = myCachedRoutes.find(key);
     563       465910 :     if (routeIt != myCachedRoutes.end()) {
     564              :         return routeIt->second;
     565              :     }
     566              :     return nullptr;
     567              : }
     568              : 
     569              : 
     570              : void
     571         8147 : MSRoutingEngine::initRouter(SUMOVehicle* vehicle) {
     572         8147 :     OptionsCont& oc = OptionsCont::getOptions();
     573         8147 :     const std::string routingAlgorithm = oc.getString("routing-algorithm");
     574         8147 :     const bool hasPermissions = MSNet::getInstance()->hasPermissions();
     575         8147 :     myBikeSpeeds = oc.getBool("device.rerouting.bike-speeds");
     576         8147 :     myEffortFunc = ((myHaveExtras || myBikeSpeeds) ? &MSRoutingEngine::getEffortExtra : &MSRoutingEngine::getEffort);
     577              : 
     578              :     SUMOAbstractRouter<MSEdge, SUMOVehicle>* router = nullptr;
     579         8147 :     if (routingAlgorithm == "dijkstra") {
     580         7616 :         router = new DijkstraRouter<MSEdge, SUMOVehicle>(MSEdge::getAllEdges(), true, myEffortFunc, nullptr, false, nullptr, true);
     581          531 :     } else if (routingAlgorithm == "astar") {
     582              :         typedef AStarRouter<MSEdge, SUMOVehicle, MSMapMatcher> AStar;
     583              :         std::shared_ptr<const AStar::LookupTable> lookup = nullptr;
     584          568 :         if (oc.isSet("astar.all-distances")) {
     585            0 :             lookup = std::make_shared<const AStar::FLT>(oc.getString("astar.all-distances"), (int)MSEdge::getAllEdges().size());
     586          568 :         } else if (oc.isSet("astar.landmark-distances") && vehicle != nullptr) {
     587           35 :             const double speedFactor = vehicle->getChosenSpeedFactor();
     588              :             // we need an exemplary vehicle with speedFactor 1
     589           35 :             vehicle->setChosenSpeedFactor(1);
     590              :             CHRouterWrapper<MSEdge, SUMOVehicle> chrouter(
     591           35 :                 MSEdge::getAllEdges(), true, &MSNet::getTravelTime,
     592          105 :                 string2time(oc.getString("begin")), string2time(oc.getString("end")), SUMOTime_MAX, hasPermissions, 1);
     593           35 :             lookup = std::make_shared<const AStar::LMLT>(oc.getString("astar.landmark-distances"), MSEdge::getAllEdges(), &chrouter,
     594           70 :                      nullptr, vehicle, "", oc.getInt("device.rerouting.threads"), MSNet::getInstance()->getMapMatcher());
     595           35 :             vehicle->setChosenSpeedFactor(speedFactor);
     596           35 :         }
     597          852 :         router = new AStar(MSEdge::getAllEdges(), true, myEffortFunc, lookup, true);
     598          247 :     } else if (routingAlgorithm == "CH" && !hasPermissions) {
     599            0 :         const SUMOTime weightPeriod = myAdaptationInterval > 0 ? myAdaptationInterval : SUMOTime_MAX;
     600              :         router = new CHRouter<MSEdge, SUMOVehicle>(
     601            0 :             MSEdge::getAllEdges(), true, myEffortFunc, vehicle == nullptr ? SVC_PASSENGER : vehicle->getVClass(), weightPeriod, true, false);
     602          247 :     } else if (routingAlgorithm == "CHWrapper" || routingAlgorithm == "CH") {
     603              :         // use CHWrapper instead of CH if the net has permissions
     604           18 :         const SUMOTime weightPeriod = myAdaptationInterval > 0 ? myAdaptationInterval : SUMOTime_MAX;
     605              :         router = new CHRouterWrapper<MSEdge, SUMOVehicle>(
     606           18 :             MSEdge::getAllEdges(), true, myEffortFunc,
     607           54 :             string2time(oc.getString("begin")), string2time(oc.getString("end")), weightPeriod, hasPermissions, oc.getInt("device.rerouting.threads"));
     608          229 :     } else if (routingAlgorithm == "CCH") {
     609              :         // CCH metrics are keyed by vehicle TYPE and filled with a reference
     610              :         // vehicle of the type (customizeCCH), mirroring duarouter's
     611              :         // RODUACCHMetrics: type/class-specific routing preferences, the
     612              :         // bicycle speed table, the type's maximum speed and the static
     613              :         // priority multiplier are captured exactly per metric.
     614              :         // weights.random-factor freezes one realization per metric -- the
     615              :         // same approximation CHRouterWrapper makes when building its
     616              :         // hierarchies; exact per-vehicle randomization remains the domain of
     617              :         // dijkstra and astar.
     618          229 :         initCCH();  // build the immutable topology + publish an initial metric (once)
     619              :         // embedded fallback for non-passenger / prohibited / unreachable queries
     620              :         SUMOAbstractRouter<MSEdge, SUMOVehicle>* fallback =
     621          229 :             new AStarRouter<MSEdge, SUMOVehicle, MSMapMatcher>(MSEdge::getAllEdges(), true, myEffortFunc, nullptr, true);
     622              :         router = new CCHRouter<MSEdge, SUMOVehicle, MSCCHGraph>(
     623          229 :             myCCHGraph, &MSRoutingEngine::getPublishedCCHMetric, myEffortFunc, true, fallback);
     624              :     } else {
     625            0 :         throw ProcessError(TLF("Unknown routing algorithm '%'!", routingAlgorithm));
     626              :     }
     627              : 
     628              :     RailwayRouter<MSEdge, SUMOVehicle>* railRouter = nullptr;
     629         8147 :     if (MSNet::getInstance()->hasBidiEdges()) {
     630          580 :         railRouter = new RailwayRouter<MSEdge, SUMOVehicle>(MSEdge::getAllEdges(), true, myEffortFunc, nullptr, false, true, false,
     631              :                 oc.getFloat("railway.max-train-length"),
     632         1160 :                 oc.getFloat("weights.reversal-penalty"));
     633              :     }
     634         9071 :     const int carWalk = SUMOVehicleParserHelper::parseCarWalkTransfer(oc, MSDevice_Taxi::hasFleet() || MSNet::getInstance()->getInsertionControl().hasTaxiFlow());
     635         8147 :     const double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
     636         8147 :     MSTransportableRouter* transRouter = new MSTransportableRouter(MSNet::adaptIntermodalRouter, carWalk, taxiWait, routingAlgorithm, 0);
     637         8147 :     myRouterProvider = new MSRouterProvider(router, nullptr, transRouter, railRouter);
     638              : #ifndef THREAD_POOL
     639              : #ifdef HAVE_FOX
     640         8147 :     MFXWorkerThread::Pool& threadPool = MSNet::getInstance()->getEdgeControl().getThreadPool();
     641         8147 :     if (threadPool.size() > 0) {
     642              :         const std::vector<MFXWorkerThread*>& threads = threadPool.getWorkers();
     643         1135 :         if (static_cast<MSEdgeControl::WorkerThread*>(threads.front())->setRouterProvider(myRouterProvider)) {
     644         4462 :             for (std::vector<MFXWorkerThread*>::const_iterator t = threads.begin() + 1; t != threads.end(); ++t) {
     645         3327 :                 static_cast<MSEdgeControl::WorkerThread*>(*t)->setRouterProvider(myRouterProvider->clone());
     646              :             }
     647              :         }
     648              :     }
     649              : #endif
     650              : #endif
     651         8147 : }
     652              : 
     653              : 
     654              : void
     655      2272151 : MSRoutingEngine::reroute(SUMOVehicle& vehicle, const SUMOTime currentTime, const std::string& info,
     656              :                          const bool onInit, const bool silent, const Prohibitions& prohibited) {
     657      2272151 :     if (myRouterProvider == nullptr) {
     658         7699 :         initRouter(&vehicle);
     659              :     }
     660      2272151 :     auto& router = myRouterProvider->getVehicleRouter(vehicle.getVClass());
     661              : #ifndef THREAD_POOL
     662              : #ifdef HAVE_FOX
     663      2272151 :     MFXWorkerThread::Pool& threadPool = MSNet::getInstance()->getEdgeControl().getThreadPool();
     664      2272151 :     if (threadPool.size() > 0) {
     665       171961 :         threadPool.add(new RoutingTask(vehicle, currentTime, info, onInit, silent, prohibited));
     666       171961 :         return;
     667              :     }
     668              : #endif
     669              : #endif
     670      2100190 :     if (!prohibited.empty()) {
     671            4 :         router.prohibit(prohibited);
     672              :     }
     673              :     try {
     674      2100190 :         vehicle.reroute(currentTime, info, router, onInit, myWithTaz, silent);
     675          109 :     } catch (ProcessError&) {
     676          109 :         if (!silent) {
     677          109 :             if (!prohibited.empty()) {
     678            0 :                 router.prohibit(Prohibitions());
     679              :             }
     680          109 :             throw;
     681              :         }
     682          109 :     }
     683      2100081 :     if (!prohibited.empty()) {
     684            8 :         router.prohibit(Prohibitions());
     685              :     }
     686              : }
     687              : 
     688              : 
     689              : void
     690          136 : MSRoutingEngine::reroute(MSTransportable& t, const SUMOTime currentTime, const std::string& info,
     691              :                          const bool onInit, const bool silent, const Prohibitions& prohibited) {
     692          136 :     MSTransportableRouter& router = getIntermodalRouterTT(t.getRNGIndex(), prohibited);
     693              : #ifndef THREAD_POOL
     694              : #ifdef HAVE_FOX
     695          136 :     MFXWorkerThread::Pool& threadPool = MSNet::getInstance()->getEdgeControl().getThreadPool();
     696          136 :     if (threadPool.size() > 0) {
     697              :         // threadPool.add(new RoutingTask(t, currentTime, info, onInit, silent, prohibited));
     698              :         return;
     699              :     }
     700              : #endif
     701              : #endif
     702          118 :     if (!prohibited.empty()) {
     703            0 :         router.prohibit(prohibited);
     704              :     }
     705              :     try {
     706          118 :         t.reroute(currentTime, info, router, onInit, myWithTaz, silent);
     707            0 :     } catch (ProcessError&) {
     708            0 :         if (!silent) {
     709            0 :             if (!prohibited.empty()) {
     710            0 :                 router.prohibit(Prohibitions());
     711              :             }
     712            0 :             throw;
     713              :         }
     714            0 :     }
     715          118 :     if (!prohibited.empty()) {
     716            0 :         router.prohibit(Prohibitions());
     717              :     }
     718              : }
     719              : 
     720              : 
     721              : void
     722            9 : MSRoutingEngine::setEdgeTravelTime(const MSEdge* const edge, const double travelTime) {
     723            9 :     myEdgeSpeeds[edge->getNumericalID()] = edge->getLength() / travelTime;
     724            9 : }
     725              : 
     726              : void
     727        13518 : MSRoutingEngine::addEdgeTravelTime(const MSEdge& edge, const SUMOTime travelTime) {
     728        13518 :     TimeAndCount& tc = myEdgeTravelTimes[edge.getNumericalID()];
     729        13518 :     tc.first += travelTime;
     730        13518 :     tc.second += 1;
     731        13518 : }
     732              : 
     733              : 
     734              : MSVehicleRouter&
     735       633538 : MSRoutingEngine::getRouterTT(const int rngIndex, SUMOVehicleClass svc, const Prohibitions& prohibited) {
     736       633538 :     if (myRouterProvider == nullptr) {
     737          186 :         initWeightUpdate();
     738          186 :         initEdgeWeights(svc);
     739          186 :         initRouter();
     740              :     }
     741              : #ifndef THREAD_POOL
     742              : #ifdef HAVE_FOX
     743       633538 :     MFXWorkerThread::Pool& threadPool = MSNet::getInstance()->getEdgeControl().getThreadPool();
     744       633538 :     if (threadPool.size() > 0) {
     745        33930 :         auto& router = static_cast<MSEdgeControl::WorkerThread*>(threadPool.getWorkers()[rngIndex % MSGlobals::gNumThreads])->getRouter(svc);
     746        33930 :         router.prohibit(prohibited);
     747        33930 :         return router;
     748              :     }
     749              : #else
     750              :     UNUSED_PARAMETER(rngIndex);
     751              : #endif
     752              : #endif
     753      1199216 :     myRouterProvider->getVehicleRouter(svc).prohibit(prohibited);
     754       599608 :     return myRouterProvider->getVehicleRouter(svc);
     755              : }
     756              : 
     757              : 
     758              : MSTransportableRouter&
     759         4651 : MSRoutingEngine::getIntermodalRouterTT(const int rngIndex, const Prohibitions& prohibited) {
     760         4651 :     if (myRouterProvider == nullptr) {
     761          262 :         initWeightUpdate();
     762          262 :         initEdgeWeights(SVC_PEDESTRIAN);
     763          262 :         initRouter();
     764              :     }
     765              : #ifndef THREAD_POOL
     766              : #ifdef HAVE_FOX
     767         4651 :     MFXWorkerThread::Pool& threadPool = MSNet::getInstance()->getEdgeControl().getThreadPool();
     768         4651 :     if (threadPool.size() > 0) {
     769         4533 :         auto& router = static_cast<MSEdgeControl::WorkerThread*>(threadPool.getWorkers()[rngIndex % MSGlobals::gNumThreads])->getIntermodalRouter();
     770         4533 :         router.prohibit(prohibited);
     771         4533 :         return router;
     772              :     }
     773              : #else
     774              :     UNUSED_PARAMETER(rngIndex);
     775              : #endif
     776              : #endif
     777          118 :     myRouterProvider->getIntermodalRouter().prohibit(prohibited);
     778          118 :     return myRouterProvider->getIntermodalRouter();
     779              : }
     780              : 
     781              : 
     782              : void
     783        85961 : MSRoutingEngine::cleanupCCH() {
     784              :     // free the CCH state so a subsequent load (libsumo / GUI reload) rebuilds
     785              :     // it against the new network; the router clones referencing it were
     786              :     // deleted together with the worker threads / router provider.
     787              :     // Deleting the metric families' owned ref vehicles dereferences their
     788              :     // MSVehicleType*, so this must run BEFORE MSNet deletes its
     789              :     // MSVehicleControl (see the call in ~MSNet); the nullptr checks below
     790              :     // make a second call from cleanup() a safe no-op.
     791        85961 :     delete myCCHLive;
     792        85961 :     myCCHLive = nullptr;
     793        85961 :     delete myCCHFreeflow;
     794        85961 :     myCCHFreeflow = nullptr;
     795        85961 :     delete myCCHGraph;
     796        85961 :     myCCHGraph = nullptr;
     797        85961 : }
     798              : 
     799              : 
     800              : void
     801        43126 : MSRoutingEngine::cleanup() {
     802        43126 :     myAdaptationInterval = -1; // responsible for triggering initEdgeWeights
     803              :     myPastEdgeSpeeds.clear();
     804              :     myEdgeSpeeds.clear();
     805              :     myEdgeTravelTimes.clear();
     806              :     myPastEdgeBikeSpeeds.clear();
     807              :     myEdgeBikeSpeeds.clear();
     808              :     // @todo recheck. calling release crashes in parallel routing
     809              :     //for (auto& item : myCachedRoutes) {
     810              :     //    item.second->release();
     811              :     //}
     812              :     {
     813              : #ifdef HAVE_FOX
     814              :         FXMutexLock lock(myRouteCacheMutex);
     815              : #endif
     816              :         myCachedRoutes.clear();
     817              :     }
     818        43126 :     myAdaptationStepsIndex = 0;
     819        43126 :     cleanupCCH();
     820              : #ifdef HAVE_FOX
     821        43126 :     if (MSGlobals::gNumThreads > 1) {
     822              :         // router deletion is done in thread destructor
     823         4561 :         myRouterProvider = nullptr;
     824         4561 :         return;
     825              :     }
     826              : #endif
     827        38565 :     delete myRouterProvider;
     828        38565 :     myRouterProvider = nullptr;
     829              : }
     830              : 
     831              : 
     832              : void
     833          535 : MSRoutingEngine::saveState(OutputDevice& out) {
     834          535 :     if (myEdgeSpeeds.size() == 0) {
     835              :         return;
     836              :     }
     837          116 :     out.openTag(SUMO_TAG_ROUTINGENGINE);
     838          116 :     out.writeAttr(SUMO_ATTR_LAST, myLastAdaptation);
     839          116 :     out.writeAttr(SUMO_ATTR_INDEX, myAdaptationStepsIndex);
     840          116 :     const MSEdgeVector& edges = MSNet::getInstance()->getEdgeControl().getEdges();
     841         9390 :     for (const MSEdge* const e : edges) {
     842            0 :         if (e->isDelayed()) {
     843              :             const int id = e->getNumericalID();
     844         1434 :             out.openTag(SUMO_TAG_EDGE);
     845         1434 :             out.writeAttr(SUMO_ATTR_ID, e->getID());
     846         1434 :             out.writeAttr(SUMO_ATTR_SPEED, myEdgeSpeeds[id]);
     847         1434 :             if (myAdaptationSteps > 0) {
     848         1434 :                 out.writeAttr(SUMO_ATTR_PASTSPEED, myPastEdgeSpeeds[id]);
     849              :             }
     850         1434 :             if (myBikeSpeeds) {
     851            0 :                 out.writeAttr(SUMO_ATTR_BIKESPEED, myEdgeBikeSpeeds[id]);
     852            0 :                 if (myAdaptationSteps > 0) {
     853            0 :                     out.writeAttr(SUMO_ATTR_PASTBIKESPEED, myPastEdgeBikeSpeeds[id]);
     854              :                 }
     855              :             }
     856         2868 :             out.closeTag();
     857              :         }
     858              :     }
     859          232 :     out.closeTag();
     860              : }
     861              : 
     862              : 
     863              : void
     864         1818 : MSRoutingEngine::loadState(const SUMOSAXAttributes& attrs) {
     865         3636 :     const MSEdge* const e = MSEdge::dictionary(attrs.getString(SUMO_ATTR_ID));
     866              :     e->markDelayed();
     867              :     const int id = e->getNumericalID();
     868              :     bool checkedSteps = false;
     869              :     bool checkedBikeSpeeds = false;
     870         1818 :     bool ok = true;
     871         1818 :     if ((int)myEdgeSpeeds.size() > id) {
     872         1818 :         myEdgeSpeeds[id] = attrs.get<double>(SUMO_ATTR_SPEED, nullptr, ok);
     873         1818 :         if (myBikeSpeeds) {
     874            0 :             if (attrs.hasAttribute(SUMO_ATTR_BIKESPEED)) {
     875            0 :                 myEdgeBikeSpeeds[id] = attrs.get<double>(SUMO_ATTR_BIKESPEED, nullptr, ok);
     876              :             } else if (!checkedBikeSpeeds) {
     877              :                 checkedBikeSpeeds = true;
     878            0 :                 WRITE_WARNING("Bike speeds missing in loaded state");
     879              :             }
     880              :         }
     881         1818 :         if (myAdaptationSteps > 0) {
     882         1818 :             const std::vector<double> speeds = attrs.getOpt<std::vector<double> >(SUMO_ATTR_PASTSPEED, nullptr, ok);
     883         1818 :             if ((int)speeds.size() == myAdaptationSteps) {
     884         1818 :                 myPastEdgeSpeeds[id] = speeds;
     885         1818 :                 if (myBikeSpeeds && attrs.hasAttribute(SUMO_ATTR_PASTBIKESPEED)) {
     886            0 :                     myPastEdgeBikeSpeeds[id] = attrs.getOpt<std::vector<double> >(SUMO_ATTR_PASTBIKESPEED, nullptr, ok);
     887              :                 }
     888              :             } else if (!checkedSteps) {
     889              :                 checkedSteps = true;
     890            0 :                 WRITE_WARNING("Number of adaptation speeds in loaded state doesn't match option --device.rerouting.adaptation-steps");
     891              :             }
     892         1818 :         }
     893              :     }
     894         1818 : }
     895              : 
     896              : 
     897              : #ifdef HAVE_FOX
     898              : void
     899    420310354 : MSRoutingEngine::waitForAll() {
     900              : #ifndef THREAD_POOL
     901    420310354 :     MFXWorkerThread::Pool& threadPool = MSNet::getInstance()->getEdgeControl().getThreadPool();
     902    420310354 :     if (threadPool.size() > 0) {
     903    241062860 :         threadPool.waitAll();
     904              :     }
     905              : #endif
     906    420310329 : }
     907              : 
     908              : 
     909              : // ---------------------------------------------------------------------------
     910              : // MSRoutingEngine::RoutingTask-methods
     911              : // ---------------------------------------------------------------------------
     912              : void
     913       171961 : MSRoutingEngine::RoutingTask::run(MFXWorkerThread* context) {
     914       171961 :     SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = static_cast<MSEdgeControl::WorkerThread*>(context)->getRouter(myVehicle.getVClass());
     915       171961 :     if (!myProhibited.empty()) {
     916            2 :         router.prohibit(myProhibited);
     917              :     }
     918              :     try {
     919       171961 :         myVehicle.reroute(myTime, myInfo, router, myOnInit, myWithTaz, mySilent);
     920           25 :     } catch (ProcessError&) {
     921           25 :         if (!mySilent) {
     922           25 :             if (!myProhibited.empty()) {
     923            0 :                 router.prohibit(Prohibitions());
     924              :             }
     925           25 :             throw;
     926              :         }
     927           25 :     }
     928       171936 :     if (!myProhibited.empty()) {
     929            4 :         router.prohibit(Prohibitions());
     930              :     }
     931       171936 :     const MSEdge* source = *myVehicle.getRoute().begin();
     932       171936 :     const MSEdge* dest = myVehicle.getRoute().getLastEdge();
     933       171936 :     if (source->isTazConnector() && dest->isTazConnector()) {
     934            4 :         const std::pair<const MSEdge*, const MSEdge*> key = std::make_pair(source, dest);
     935              :         FXMutexLock lock(myRouteCacheMutex);
     936            4 :         if (MSRoutingEngine::myCachedRoutes.find(key) == MSRoutingEngine::myCachedRoutes.end()) {
     937            6 :             MSRoutingEngine::myCachedRoutes[key] = myVehicle.getRoutePtr();
     938              :         }
     939              :     }
     940       171936 : }
     941              : 
     942              : 
     943              : #endif
     944              : 
     945              : 
     946              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1