LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDevice_Routing.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 88.7 % 221 196
Test Date: 2026-09-23 15:43:02 Functions: 100.0 % 17 17

            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    MSDevice_Routing.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 <microsim/MSNet.h>
      27              : #include <microsim/MSLane.h>
      28              : #include <microsim/MSEdge.h>
      29              : #include <microsim/MSEdgeControl.h>
      30              : #include <microsim/MSEventControl.h>
      31              : #include <microsim/MSGlobals.h>
      32              : #include <microsim/MSVehicleControl.h>
      33              : #include <utils/options/OptionsCont.h>
      34              : #include <utils/common/WrappingCommand.h>
      35              : #include <utils/common/StringUtils.h>
      36              : #include <utils/xml/SUMOSAXAttributes.h>
      37              : #include "MSRoutingEngine.h"
      38              : #include "MSDevice_Routing.h"
      39              : 
      40              : 
      41              : // ===========================================================================
      42              : // method definitions
      43              : // ===========================================================================
      44              : // ---------------------------------------------------------------------------
      45              : // static initialisation methods
      46              : // ---------------------------------------------------------------------------
      47              : void
      48        46292 : MSDevice_Routing::insertOptions(OptionsCont& oc) {
      49        92584 :     insertDefaultAssignmentOptions("rerouting", "Routing", oc);
      50              : 
      51        92584 :     oc.doRegister("device.rerouting.period", new Option_String("0", "TIME"));
      52        92584 :     oc.addSynonyme("device.rerouting.period", "device.routing.period", true);
      53        92584 :     oc.addDescription("device.rerouting.period", "Routing", TL("The period with which the vehicle shall be rerouted"));
      54              : 
      55        92584 :     oc.doRegister("device.rerouting.pre-period", new Option_String("60", "TIME"));
      56        92584 :     oc.addSynonyme("device.rerouting.pre-period", "device.routing.pre-period", true);
      57        92584 :     oc.addDescription("device.rerouting.pre-period", "Routing", TL("The rerouting period before depart"));
      58              : 
      59        46292 :     oc.doRegister("device.rerouting.adaptation-weight", new Option_Float(0));
      60        92584 :     oc.addSynonyme("device.rerouting.adaptation-weight", "device.routing.adaptation-weight", true);
      61        92584 :     oc.addDescription("device.rerouting.adaptation-weight", "Routing", TL("The weight of prior edge weights for exponential moving average"));
      62              : 
      63        46292 :     oc.doRegister("device.rerouting.adaptation-steps", new Option_Integer(180));
      64        92584 :     oc.addSynonyme("device.rerouting.adaptation-steps", "device.routing.adaptation-steps", true);
      65        92584 :     oc.addDescription("device.rerouting.adaptation-steps", "Routing", TL("The number of steps for moving average weight of prior edge weights"));
      66              : 
      67        92584 :     oc.doRegister("device.rerouting.adaptation-interval", new Option_String("1", "TIME"));
      68        92584 :     oc.addSynonyme("device.rerouting.adaptation-interval", "device.routing.adaptation-interval", true);
      69        92584 :     oc.addDescription("device.rerouting.adaptation-interval", "Routing", TL("The interval for updating the edge weights"));
      70              : 
      71        46292 :     oc.doRegister("device.rerouting.cch-update-threshold.factor", new Option_Float(1));
      72        92584 :     oc.addDescription("device.rerouting.cch-update-threshold.factor", "Routing", TL("Only propagate an arc weight into the CCH metric if it changed by more than the given factor"));
      73              : 
      74        92584 :     oc.doRegister("device.rerouting.cch-update-threshold.constant", new Option_String("0", "TIME"));
      75        92584 :     oc.addDescription("device.rerouting.cch-update-threshold.constant", "Routing", TL("Only propagate an arc weight into the CCH metric if it changed by more than the given TIME"));
      76        46292 :     oc.doRegister("device.rerouting.cch-ensemble", new Option_Integer(1));
      77        92584 :     oc.addDescription("device.rerouting.cch-ensemble", "Routing", TL("Keep this many frozen weights.random-factor realizations (CCH metrics) per vehicle type and assign vehicles to them by a stable id hash"));
      78              : 
      79        46292 :     oc.doRegister("device.rerouting.threshold.factor", new Option_Float(1));
      80        92584 :     oc.addDescription("device.rerouting.threshold.factor", "Routing", TL("Only reroute if the new route is faster than the current route by the given factor"));
      81              : 
      82        92584 :     oc.doRegister("device.rerouting.threshold.constant", new Option_String("0", "TIME"));
      83        92584 :     oc.addDescription("device.rerouting.threshold.constant", "Routing", TL("Only reroute if the new route is faster than the current route by the given TIME"));
      84              : 
      85        46292 :     oc.doRegister("device.rerouting.invalidation", new Option_Bool(false));
      86        92584 :     oc.addDescription("device.rerouting.invalidation", "Routing", TL("Only perform a periodic reroute when the current route's remaining cost has drifted beyond the threshold (cheap re-scoring gate before the full reroute)"));
      87              : 
      88        46292 :     oc.doRegister("device.rerouting.with-taz", new Option_Bool(false));
      89        92584 :     oc.addSynonyme("device.rerouting.with-taz", "device.routing.with-taz", true);
      90        92584 :     oc.addSynonyme("device.rerouting.with-taz", "with-taz");
      91        92584 :     oc.addDescription("device.rerouting.with-taz", "Routing", TL("Use zones (districts) as routing start- and endpoints"));
      92              : 
      93        92584 :     oc.doRegister("device.rerouting.mode", new Option_String("0"));
      94        92584 :     oc.addDescription("device.rerouting.mode", "Routing", TL("Set routing flags (8 ignores temporary blockages)"));
      95              : 
      96        46292 :     oc.doRegister("device.rerouting.init-with-loaded-weights", new Option_Bool(false));
      97        92584 :     oc.addDescription("device.rerouting.init-with-loaded-weights", "Routing", TL("Use weight files given with option --weight-files for initializing edge weights"));
      98              : 
      99        46292 :     oc.doRegister("device.rerouting.threads", new Option_Integer(0));
     100        92584 :     oc.addSynonyme("device.rerouting.threads", "routing-threads");
     101        92584 :     oc.addDescription("device.rerouting.threads", "Routing", TL("The number of parallel execution threads used for rerouting"));
     102              : 
     103        46292 :     oc.doRegister("device.rerouting.synchronize", new Option_Bool(false));
     104        92584 :     oc.addDescription("device.rerouting.synchronize", "Routing", TL("Let rerouting happen at the same time for all vehicles"));
     105              : 
     106        46292 :     oc.doRegister("device.rerouting.railsignal", new Option_Bool(false));
     107        92584 :     oc.addDescription("device.rerouting.railsignal", "Routing", TL("Allow rerouting triggered by rail signals."));
     108              : 
     109        46292 :     oc.doRegister("device.rerouting.bike-speeds", new Option_Bool(false));
     110        92584 :     oc.addDescription("device.rerouting.bike-speeds", "Routing", TL("Compute separate average speeds for bicycles"));
     111              : 
     112        46292 :     oc.doRegister("device.rerouting.output", new Option_FileName());
     113        92584 :     oc.addDescription("device.rerouting.output", "Routing", TL("Save adapting weights to FILE"));
     114        46292 : }
     115              : 
     116              : 
     117              : bool
     118        45592 : MSDevice_Routing::checkOptions(OptionsCont& oc) {
     119              :     bool ok = true;
     120        45952 :     if (!oc.isDefault("device.rerouting.adaptation-steps") && !oc.isDefault("device.rerouting.adaptation-weight")) {
     121            0 :         WRITE_ERROR(TL("Only one of the options 'device.rerouting.adaptation-steps' or 'device.rerouting.adaptation-weight' may be given."));
     122              :         ok = false;
     123              :     }
     124        91184 :     if (oc.getFloat("weights.random-factor") < 1) {
     125            0 :         WRITE_ERROR(TL("weights.random-factor cannot be less than 1"));
     126              :         ok = false;
     127              :     }
     128        91184 :     if (string2time(oc.getString("device.rerouting.adaptation-interval")) < 0) {
     129           16 :         WRITE_ERROR(TL("Negative value for device.rerouting.adaptation-interval!"));
     130              :         ok = false;
     131              :     }
     132       136776 :     if (oc.getFloat("device.rerouting.adaptation-weight") < 0.  ||
     133       136776 :             oc.getFloat("device.rerouting.adaptation-weight") > 1.) {
     134            0 :         WRITE_ERROR(TL("The value for device.rerouting.adaptation-weight must be between 0 and 1!"));
     135              :         ok = false;
     136              :     }
     137              : #ifndef HAVE_FOX
     138              :     if (oc.getInt("device.rerouting.threads") > 1) {
     139              :         WRITE_ERROR(TL("Parallel routing is only possible when compiled with Fox."));
     140              :         ok = false;
     141              :     }
     142              : #endif
     143        50198 :     if (oc.getInt("threads") > 1 && oc.getInt("device.rerouting.threads") > 1 && oc.getInt("threads") != oc.getInt("device.rerouting.threads")) {
     144           18 :         WRITE_WARNING(TL("Adapting number of routing threads to number of simulation threads."));
     145              :     }
     146        45592 :     return ok;
     147              : }
     148              : 
     149              : 
     150              : void
     151      5489596 : MSDevice_Routing::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
     152      5489596 :     const OptionsCont& oc = OptionsCont::getOptions();
     153      5489596 :     const bool equip = equippedByDefaultAssignmentOptions(oc, "rerouting", v, false);
     154      5489590 :     if (v.getParameter().wasSet(VEHPARS_FORCE_REROUTE) || equip) {
     155              :         // route computation is enabled
     156              :         // for implicitly equipped vehicles (trips, flows), option probability
     157              :         // can still be used to disable periodic rerouting after insertion for
     158              :         // parts of the fleet
     159      1243552 :         const SUMOTime period = (equip || (
     160      2486126 :                                      oc.isDefault("device.rerouting.probability") &&
     161      3898187 :                                      v.getFloatParam("device.rerouting.probability") == oc.getFloat("device.rerouting.probability"))
     162      4068572 :                                  ? v.getTimeParam("device.rerouting.period") : 0);
     163      1413039 :         const SUMOTime prePeriod = MAX2((SUMOTime)0, v.getTimeParam("device.rerouting.pre-period"));
     164      1413039 :         MSRoutingEngine::initWeightUpdate();
     165              :         // build the device
     166      2826078 :         into.push_back(new MSDevice_Routing(v, "routing_" + v.getID(), period, prePeriod));
     167              :     }
     168      5489590 : }
     169              : 
     170              : 
     171              : // ---------------------------------------------------------------------------
     172              : // MSDevice_Routing-methods
     173              : // ---------------------------------------------------------------------------
     174      1413039 : MSDevice_Routing::MSDevice_Routing(SUMOVehicle& holder, const std::string& id,
     175      1413039 :                                    SUMOTime period, SUMOTime preInsertionPeriod) :
     176              :     MSVehicleDevice(holder, id),
     177      1413039 :     myPeriod(period),
     178      1413039 :     myPreInsertionPeriod(preInsertionPeriod),
     179      1413039 :     myLastRouting(-1),
     180      1413039 :     mySkipRouting(-1),
     181      1413039 :     myRerouteCommand(nullptr),
     182      1413039 :     myRerouteRailSignal(holder.getBoolParam("device.rerouting.railsignal", true)),
     183      1413039 :     myLastLaneEntryTime(-1),
     184      1413039 :     myRerouteAfterStop(false),
     185      1413039 :     myThresholdFactor(holder.getFloatParam("device.rerouting.threshold.factor", true, 1)),
     186      1413039 :     myThresholdTime(STEPS2TIME(holder.getTimeParam("device.rerouting.threshold.constant", true, 0))),
     187      1413039 :     myActive(true),
     188      1413039 :     myInvalidation(OptionsCont::getOptions().getBool("device.rerouting.invalidation")),
     189      1413039 :     myLastRouteCost(-1.) {
     190      1413039 :     if (myPreInsertionPeriod > 0 || holder.getParameter().wasSet(VEHPARS_FORCE_REROUTE)) {
     191              :         // we do always a pre insertion reroute for trips to fill the best lanes of the vehicle with somehow meaningful values (especially for deaprtLane="best")
     192      1412094 :         myRerouteCommand = new WrappingCommand<MSDevice_Routing>(this, &MSDevice_Routing::preInsertionReroute);
     193              :         // if we don't update the edge weights, we might as well reroute now and hopefully use our threads better
     194      1412094 :         const SUMOTime execTime = MSRoutingEngine::hasEdgeUpdates() ? holder.getParameter().depart : -1;
     195      1412094 :         MSNet::getInstance()->getInsertionEvents()->addEvent(myRerouteCommand, execTime);
     196              :     }
     197      1413039 : }
     198              : 
     199              : 
     200      2826066 : MSDevice_Routing::~MSDevice_Routing() {
     201              :     // make the rerouting command invalid if there is one
     202      1413033 :     if (myRerouteCommand != nullptr) {
     203              :         myRerouteCommand->deschedule();
     204              :     }
     205      2826066 : }
     206              : 
     207              : 
     208              : bool
     209      1179266 : MSDevice_Routing::notifyEnter(SUMOTrafficObject& /*veh*/, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     210      1179266 :     if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
     211      1139942 :         if (myRerouteCommand == nullptr && myPreInsertionPeriod > 0 && myHolder.getDepartDelay() > myPreInsertionPeriod) {
     212              :             // pre-insertion rerouting was disabled. Reroute once if insertion was delayed
     213              :             // this is happening in the run thread (not inbeginOfTimestepEvents) so we cannot safely use the threadPool
     214      1732647 :             myHolder.reroute(MSNet::getInstance()->getCurrentTimeStep(), "device.rerouting",
     215      1155098 :                              MSRoutingEngine::getRouterTT(myHolder.getRNGIndex(), myHolder.getVClass()),
     216              :                              true, MSRoutingEngine::withTaz(), false);
     217              :         }
     218              :         // build repetition trigger if routing shall be done more often
     219      1139942 :         rebuildRerouteCommand(SIMSTEP + myPeriod);
     220              :     }
     221      1179266 :     if (MSGlobals::gWeightsSeparateTurns > 0 && enteredLane != nullptr) {
     222        43622 :         if (reason == MSMoveReminder::NOTIFICATION_JUNCTION) {
     223        37512 :             const SUMOTime t = SIMSTEP;
     224        37512 :             if (myLastLaneEntryTime >= 0 && enteredLane->isInternal()) {
     225              :                 // record travel time on the previous edge but store on the internal ledge
     226        13518 :                 MSRoutingEngine::addEdgeTravelTime(enteredLane->getEdge(), t - myLastLaneEntryTime);
     227              :             }
     228        37512 :             myLastLaneEntryTime = t;
     229              :         }
     230        43622 :         return true;
     231              :     } else {
     232              :         return false;
     233              :     }
     234              : }
     235              : 
     236              : 
     237              : void
     238         6339 : MSDevice_Routing::notifyStopEnded() {
     239         6339 :     if (myRerouteAfterStop) {
     240          257 :         reroute(SIMSTEP);
     241          257 :         myRerouteAfterStop = false;
     242              :     }
     243         6339 : }
     244              : 
     245              : 
     246              : void
     247      1141691 : MSDevice_Routing::rebuildRerouteCommand(SUMOTime start) {
     248      1141691 :     if (myRerouteCommand != nullptr) {
     249              :         myRerouteCommand->deschedule();
     250       228966 :         myRerouteCommand = nullptr;
     251              :     }
     252      1141691 :     if (myPeriod > 0) {
     253        61780 :         myRerouteCommand = new WrappingCommand<MSDevice_Routing>(this, &MSDevice_Routing::wrappedRerouteCommandExecute);
     254       123560 :         if (OptionsCont::getOptions().getBool("device.rerouting.synchronize")) {
     255         1590 :             start -= start % myPeriod;
     256              :         }
     257              :         // ensure stable sorting of events (for repeatable routing with randomness)
     258        61780 :         myRerouteCommand->priority = (int)myHolder.getNumericalID();
     259        61780 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myRerouteCommand, start);
     260              :     }
     261      1141691 : }
     262              : 
     263              : 
     264              : SUMOTime
     265     45668764 : MSDevice_Routing::preInsertionReroute(const SUMOTime currentTime) {
     266     45668764 :     if (mySkipRouting == currentTime) {
     267     43570100 :         return DELTA_T;
     268              :     }
     269      2098664 :     if (myPreInsertionPeriod == 0) {
     270              :         // the event will deschedule and destroy itself so it does not need to be stored
     271          566 :         myRerouteCommand = nullptr;
     272              :     }
     273      2098664 :     const MSEdge* source = *myHolder.getRoute().begin();
     274      2098664 :     const MSEdge* dest = myHolder.getRoute().getLastEdge();
     275      2098664 :     if (source->isTazConnector() && dest->isTazConnector()) {
     276       465910 :         ConstMSRoutePtr cached = MSRoutingEngine::getCachedRoute(std::make_pair(source, dest));
     277       465910 :         if (cached != nullptr && cached->size() > 2) {
     278            0 :             myHolder.replaceRoute(cached, "device.rerouting", true);
     279            0 :             return myPreInsertionPeriod;
     280              :         }
     281              :     }
     282              :     try {
     283              :         std::string msg;
     284      2098664 :         if (myHolder.hasValidRouteStart(msg)) {
     285      2098642 :             reroute(currentTime, true);
     286              :         }
     287          109 :     } catch (ProcessError&) {
     288          109 :         myRerouteCommand = nullptr;
     289          109 :         throw;
     290          109 :     }
     291              :     // avoid repeated pre-insertion rerouting when the departure edge is fix and
     292              :     // the departure lane does not depend on the route
     293      3730629 :     if (myPreInsertionPeriod > 0 && !source->isTazConnector() && myHolder.getParameter().departLaneProcedure != DepartLaneDefinition::BEST_FREE) {
     294       928989 :         myRerouteCommand = nullptr;
     295       928989 :         return 0;
     296              :     }
     297      1169566 :     return myPreInsertionPeriod;
     298              : }
     299              : 
     300              : 
     301              : SUMOTime
     302       199601 : MSDevice_Routing::wrappedRerouteCommandExecute(SUMOTime currentTime) {
     303       199601 :     if (myHolder.isStopped()) {
     304        21674 :         myRerouteAfterStop = true;
     305              :     } else {
     306       177927 :         reroute(currentTime);
     307              :     }
     308       199601 :     return myPeriod;
     309              : }
     310              : 
     311              : 
     312              : void
     313      2276826 : MSDevice_Routing::reroute(const SUMOTime currentTime, const bool onInit) {
     314      2276826 :     MSRoutingEngine::initEdgeWeights(myHolder.getVClass());
     315              :     //check whether the weights did change since the last reroute
     316      2276826 :     if (myLastRouting >= MSRoutingEngine::getLastAdaptation() || !myActive) {
     317              :         return;
     318              :     }
     319              :     // Invalidation gate: even when the metric changed, skip the (expensive)
     320              :     // reroute unless THIS vehicle's remaining route has actually degraded.
     321              :     // recomputeCosts is O(remaining-route length) array reads, far cheaper
     322              :     // than a shortest-path search. Only meaningful once the vehicle is on the
     323              :     // road with a concrete route (getCurrentRouteEdge is only valid then);
     324              :     // pre-insertion / onInit reroutes always run and don't track cost.
     325      2272145 :     const bool canGate = myInvalidation && !onInit && myHolder.isOnRoad();
     326            0 :     if (canGate && myLastRouteCost >= 0.) {
     327            0 :         MSVehicleRouter& router = MSRoutingEngine::getRouterTT(myHolder.getRNGIndex(), myHolder.getVClass());
     328            0 :         const ConstMSEdgeVector remaining(myHolder.getCurrentRouteEdge(), myHolder.getRoute().end());
     329            0 :         if (!remaining.empty()) {
     330            0 :             const double costNow = router.recomputeCosts(remaining, &myHolder, currentTime);
     331            0 :             if (costNow - myLastRouteCost <= myThresholdTime && costNow <= myLastRouteCost * myThresholdFactor) {
     332            0 :                 myLastRouting = currentTime;  // route still good enough; skip the search
     333            0 :                 myLastRouteCost = costNow;
     334              :                 return;
     335              :             }
     336              :         }
     337            0 :     }
     338      2272145 :     myLastRouting = currentTime;
     339      4544290 :     MSRoutingEngine::reroute(myHolder, currentTime, "device.rerouting", onInit);
     340      2272036 :     if (myInvalidation && myHolder.isOnRoad()) {
     341            0 :         MSVehicleRouter& router = MSRoutingEngine::getRouterTT(myHolder.getRNGIndex(), myHolder.getVClass());
     342            0 :         const ConstMSEdgeVector remaining(myHolder.getCurrentRouteEdge(), myHolder.getRoute().end());
     343            0 :         myLastRouteCost = remaining.empty() ? -1. : router.recomputeCosts(remaining, &myHolder, currentTime);
     344            0 :     }
     345              : }
     346              : 
     347              : 
     348              : bool
     349       172773 : MSDevice_Routing::sufficientSaving(double oldCost, double newCost) {
     350       172773 :     if (newCost == 0) {
     351              :         return true;
     352              :     }
     353       172757 :     return (oldCost / newCost > myThresholdFactor) && (oldCost - newCost > myThresholdTime);
     354              : }
     355              : 
     356              : 
     357              : std::string
     358           36 : MSDevice_Routing::getParameter(const std::string& key) const {
     359           72 :     if (StringUtils::startsWith(key, "edge:")) {
     360           18 :         const std::string edgeID = key.substr(5);
     361           18 :         const MSEdge* edge = MSEdge::dictionary(edgeID);
     362           18 :         if (edge == nullptr) {
     363            0 :             throw InvalidArgument("Edge '" + edgeID + "' is invalid for parameter retrieval of '" + deviceName() + "'");
     364              :         }
     365           18 :         return toString(MSRoutingEngine::getEffort(edge, &myHolder, 0));
     366           18 :     } else if (key == "period") {
     367           18 :         return time2string(myPeriod);
     368              :     }
     369            0 :     throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     370              : }
     371              : 
     372              : 
     373              : void
     374           33 : MSDevice_Routing::setParameter(const std::string& key, const std::string& value) {
     375              :     double doubleValue;
     376              :     try {
     377           33 :         doubleValue = StringUtils::toDouble(value);
     378            0 :     } catch (NumberFormatException&) {
     379            0 :         throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
     380            0 :     }
     381           66 :     if (StringUtils::startsWith(key, "edge:")) {
     382            9 :         const std::string edgeID = key.substr(5);
     383            9 :         const MSEdge* edge = MSEdge::dictionary(edgeID);
     384            9 :         if (edge == nullptr) {
     385            0 :             throw InvalidArgument("Edge '" + edgeID + "' is invalid for parameter setting of '" + deviceName() + "'");
     386              :         }
     387            9 :         MSRoutingEngine::setEdgeTravelTime(edge, doubleValue);
     388           24 :     } else if (key == "period") {
     389           24 :         myPeriod = TIME2STEPS(doubleValue);
     390              :         // re-schedule routing command
     391           24 :         rebuildRerouteCommand(SIMSTEP + myPeriod);
     392              :     } else {
     393            0 :         throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     394              :     }
     395           33 : }
     396              : 
     397              : 
     398              : void
     399         3274 : MSDevice_Routing::saveState(OutputDevice& out) const {
     400         3274 :     out.openTag(SUMO_TAG_DEVICE);
     401         3274 :     out.writeAttr(SUMO_ATTR_ID, getID());
     402              :     std::vector<std::string> internals;
     403         3274 :     internals.push_back(toString(myPeriod));
     404         3274 :     internals.push_back(toString(myLastRouting));
     405         3274 :     out.writeAttr(SUMO_ATTR_STATE, toString(internals));
     406         3274 :     out.closeTag();
     407         3274 : }
     408              : 
     409              : 
     410              : void
     411         4057 : MSDevice_Routing::loadState(const SUMOSAXAttributes& attrs) {
     412         4057 :     std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
     413         4057 :     bis >> myPeriod;
     414         4057 :     bis >> myLastRouting;
     415         4057 :     if (myHolder.hasDeparted()) {
     416         1725 :         SUMOTime offset = myPeriod;
     417         1725 :         if (myPeriod > 0) {
     418          807 :             offset = ((SIMSTEP - myHolder.getDeparture()) % myPeriod);
     419          807 :             if (offset != 0) {
     420          785 :                 offset = myPeriod - offset;
     421              :             }
     422              :         }
     423         1725 :         rebuildRerouteCommand(SIMSTEP + offset);
     424              :     }
     425         4057 : }
     426              : 
     427              : 
     428              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1