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

Generated by: LCOV version 2.0-1