LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDevice_Routing.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.5 % 179 162
Test Date: 2024-11-22 15:46:21 Functions: 93.8 % 16 15

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2007-2024 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    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        43644 : MSDevice_Routing::insertOptions(OptionsCont& oc) {
      49        87288 :     insertDefaultAssignmentOptions("rerouting", "Routing", oc);
      50              : 
      51        87288 :     oc.doRegister("device.rerouting.period", new Option_String("0", "TIME"));
      52        87288 :     oc.addSynonyme("device.rerouting.period", "device.routing.period", true);
      53        87288 :     oc.addDescription("device.rerouting.period", "Routing", TL("The period with which the vehicle shall be rerouted"));
      54              : 
      55        87288 :     oc.doRegister("device.rerouting.pre-period", new Option_String("60", "TIME"));
      56        87288 :     oc.addSynonyme("device.rerouting.pre-period", "device.routing.pre-period", true);
      57        87288 :     oc.addDescription("device.rerouting.pre-period", "Routing", TL("The rerouting period before depart"));
      58              : 
      59        43644 :     oc.doRegister("device.rerouting.adaptation-weight", new Option_Float(0));
      60        87288 :     oc.addSynonyme("device.rerouting.adaptation-weight", "device.routing.adaptation-weight", true);
      61        87288 :     oc.addDescription("device.rerouting.adaptation-weight", "Routing", TL("The weight of prior edge weights for exponential moving average"));
      62              : 
      63        43644 :     oc.doRegister("device.rerouting.adaptation-steps", new Option_Integer(180));
      64        87288 :     oc.addSynonyme("device.rerouting.adaptation-steps", "device.routing.adaptation-steps", true);
      65        87288 :     oc.addDescription("device.rerouting.adaptation-steps", "Routing", TL("The number of steps for moving average weight of prior edge weights"));
      66              : 
      67        87288 :     oc.doRegister("device.rerouting.adaptation-interval", new Option_String("1", "TIME"));
      68        87288 :     oc.addSynonyme("device.rerouting.adaptation-interval", "device.routing.adaptation-interval", true);
      69        87288 :     oc.addDescription("device.rerouting.adaptation-interval", "Routing", TL("The interval for updating the edge weights"));
      70              : 
      71        43644 :     oc.doRegister("device.rerouting.with-taz", new Option_Bool(false));
      72        87288 :     oc.addSynonyme("device.rerouting.with-taz", "device.routing.with-taz", true);
      73        87288 :     oc.addSynonyme("device.rerouting.with-taz", "with-taz");
      74        87288 :     oc.addDescription("device.rerouting.with-taz", "Routing", TL("Use zones (districts) as routing start- and endpoints"));
      75              : 
      76        87288 :     oc.doRegister("device.rerouting.mode", new Option_String("0"));
      77        87288 :     oc.addDescription("device.rerouting.mode", "Routing", TL("Set routing flags (8 ignores temporary blockages)"));
      78              : 
      79        43644 :     oc.doRegister("device.rerouting.init-with-loaded-weights", new Option_Bool(false));
      80        87288 :     oc.addDescription("device.rerouting.init-with-loaded-weights", "Routing", TL("Use weight files given with option --weight-files for initializing edge weights"));
      81              : 
      82        43644 :     oc.doRegister("device.rerouting.threads", new Option_Integer(0));
      83        87288 :     oc.addSynonyme("device.rerouting.threads", "routing-threads");
      84        87288 :     oc.addDescription("device.rerouting.threads", "Routing", TL("The number of parallel execution threads used for rerouting"));
      85              : 
      86        43644 :     oc.doRegister("device.rerouting.synchronize", new Option_Bool(false));
      87        87288 :     oc.addDescription("device.rerouting.synchronize", "Routing", TL("Let rerouting happen at the same time for all vehicles"));
      88              : 
      89        43644 :     oc.doRegister("device.rerouting.railsignal", new Option_Bool(false));
      90        87288 :     oc.addDescription("device.rerouting.railsignal", "Routing", TL("Allow rerouting triggered by rail signals."));
      91              : 
      92        43644 :     oc.doRegister("device.rerouting.bike-speeds", new Option_Bool(false));
      93        87288 :     oc.addDescription("device.rerouting.bike-speeds", "Routing", TL("Compute separate average speeds for bicycles"));
      94              : 
      95        43644 :     oc.doRegister("device.rerouting.output", new Option_FileName());
      96        87288 :     oc.addDescription("device.rerouting.output", "Routing", TL("Save adapting weights to FILE"));
      97        43644 : }
      98              : 
      99              : 
     100              : bool
     101        43320 : MSDevice_Routing::checkOptions(OptionsCont& oc) {
     102              :     bool ok = true;
     103        43604 :     if (!oc.isDefault("device.rerouting.adaptation-steps") && !oc.isDefault("device.rerouting.adaptation-weight")) {
     104            0 :         WRITE_ERROR(TL("Only one of the options 'device.rerouting.adaptation-steps' or 'device.rerouting.adaptation-weight' may be given."));
     105              :         ok = false;
     106              :     }
     107        86640 :     if (oc.getFloat("weights.random-factor") < 1) {
     108            0 :         WRITE_ERROR(TL("weights.random-factor cannot be less than 1"));
     109              :         ok = false;
     110              :     }
     111        86640 :     if (string2time(oc.getString("device.rerouting.adaptation-interval")) < 0) {
     112           14 :         WRITE_ERROR(TL("Negative value for device.rerouting.adaptation-interval!"));
     113              :         ok = false;
     114              :     }
     115       129960 :     if (oc.getFloat("device.rerouting.adaptation-weight") < 0.  ||
     116       129960 :             oc.getFloat("device.rerouting.adaptation-weight") > 1.) {
     117            0 :         WRITE_ERROR(TL("The value for device.rerouting.adaptation-weight must be between 0 and 1!"));
     118              :         ok = false;
     119              :     }
     120              : #ifndef HAVE_FOX
     121              :     if (oc.getInt("device.rerouting.threads") > 1) {
     122              :         WRITE_ERROR(TL("Parallel routing is only possible when compiled with Fox."));
     123              :         ok = false;
     124              :     }
     125              : #endif
     126        47389 :     if (oc.getInt("threads") > 1 && oc.getInt("device.rerouting.threads") > 1 && oc.getInt("threads") != oc.getInt("device.rerouting.threads")) {
     127           16 :         WRITE_WARNING(TL("Adapting number of routing threads to number of simulation threads."));
     128              :     }
     129        43320 :     return ok;
     130              : }
     131              : 
     132              : 
     133              : void
     134      5104388 : MSDevice_Routing::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
     135      5104388 :     const OptionsCont& oc = OptionsCont::getOptions();
     136      5104388 :     const bool equip = equippedByDefaultAssignmentOptions(oc, "rerouting", v, false);
     137      5104382 :     if (v.getParameter().wasSet(VEHPARS_FORCE_REROUTE) || equip) {
     138              :         // route computation is enabled
     139              :         // for implicitly equipped vehicles (trips, flows), option probability
     140              :         // can still be used to disable periodic rerouting after insertion for
     141              :         // parts of the fleet
     142      1347988 :         const SUMOTime period = (equip || (
     143      2695258 :                                      oc.isDefault("device.rerouting.probability") &&
     144      4209193 :                                      v.getFloatParam("device.rerouting.probability") == oc.getFloat("device.rerouting.probability"))
     145      4376506 :                                  ? v.getTimeParam("device.rerouting.period") : 0);
     146      1514653 :         const SUMOTime prePeriod = MAX2((SUMOTime)0, v.getTimeParam("device.rerouting.pre-period"));
     147      1514653 :         MSRoutingEngine::initWeightUpdate();
     148              :         // build the device
     149      3029306 :         into.push_back(new MSDevice_Routing(v, "routing_" + v.getID(), period, prePeriod));
     150              :     }
     151      5104382 : }
     152              : 
     153              : 
     154              : // ---------------------------------------------------------------------------
     155              : // MSDevice_Routing-methods
     156              : // ---------------------------------------------------------------------------
     157      1514653 : MSDevice_Routing::MSDevice_Routing(SUMOVehicle& holder, const std::string& id,
     158      1514653 :                                    SUMOTime period, SUMOTime preInsertionPeriod) :
     159              :     MSVehicleDevice(holder, id),
     160      1514653 :     myPeriod(period),
     161      1514653 :     myPreInsertionPeriod(preInsertionPeriod),
     162      1514653 :     myLastRouting(-1),
     163      1514653 :     mySkipRouting(-1),
     164      1514653 :     myRerouteCommand(nullptr),
     165      1514653 :     myRerouteRailSignal(holder.getBoolParam("device.rerouting.railsignal", true)),
     166      1514653 :     myLastLaneEntryTime(-1),
     167      1514653 :     myRerouteAfterStop(false),
     168      1514653 :     myActive(true) {
     169      1514653 :     if (myPreInsertionPeriod > 0 || holder.getParameter().wasSet(VEHPARS_FORCE_REROUTE)) {
     170              :         // 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")
     171      1513892 :         myRerouteCommand = new WrappingCommand<MSDevice_Routing>(this, &MSDevice_Routing::preInsertionReroute);
     172              :         // if we don't update the edge weights, we might as well reroute now and hopefully use our threads better
     173      1513892 :         const SUMOTime execTime = MSRoutingEngine::hasEdgeUpdates() ? holder.getParameter().depart : -1;
     174      1513892 :         MSNet::getInstance()->getInsertionEvents()->addEvent(myRerouteCommand, execTime);
     175              :     }
     176      1514653 : }
     177              : 
     178              : 
     179      3029284 : MSDevice_Routing::~MSDevice_Routing() {
     180              :     // make the rerouting command invalid if there is one
     181      1514642 :     if (myRerouteCommand != nullptr) {
     182              :         myRerouteCommand->deschedule();
     183              :     }
     184      3029284 : }
     185              : 
     186              : 
     187              : bool
     188       966204 : MSDevice_Routing::notifyEnter(SUMOTrafficObject& /*veh*/, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     189       966204 :     if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
     190       933755 :         if (myRerouteCommand == nullptr && myPreInsertionPeriod > 0 && myHolder.getDepartDelay() > myPreInsertionPeriod) {
     191              :             // pre-insertion rerouting was disabled. Reroute once if insertion was delayed
     192              :             // this is happening in the run thread (not inbeginOfTimestepEvents) so we cannot safely use the threadPool
     193       865984 :             myHolder.reroute(MSNet::getInstance()->getCurrentTimeStep(), "device.rerouting",
     194       865984 :                              MSRoutingEngine::getRouterTT(myHolder.getRNGIndex(), myHolder.getVClass()),
     195              :                              false, MSRoutingEngine::withTaz(), false);
     196              :         }
     197              :         // build repetition trigger if routing shall be done more often
     198       933755 :         rebuildRerouteCommand();
     199              :     }
     200       966204 :     if (MSGlobals::gWeightsSeparateTurns > 0) {
     201        36105 :         if (reason == MSMoveReminder::NOTIFICATION_JUNCTION) {
     202        31105 :             const SUMOTime t = SIMSTEP;
     203        31105 :             if (myLastLaneEntryTime >= 0 && enteredLane->isInternal()) {
     204              :                 // record travel time on the previous edge but store on the internal ledge
     205        11090 :                 MSRoutingEngine::addEdgeTravelTime(enteredLane->getEdge(), t - myLastLaneEntryTime);
     206              :             }
     207        31105 :             myLastLaneEntryTime = t;
     208              :         }
     209        36105 :         return true;
     210              :     } else {
     211              :         return false;
     212              :     }
     213              : }
     214              : 
     215              : 
     216              : void
     217            0 : MSDevice_Routing::notifyStopEnded() {
     218            0 :     if (myRerouteAfterStop) {
     219            0 :         reroute(SIMSTEP);
     220            0 :         myRerouteAfterStop = false;
     221              :     }
     222            0 : }
     223              : 
     224              : 
     225              : void
     226       935134 : MSDevice_Routing::rebuildRerouteCommand() {
     227       935134 :     if (myRerouteCommand != nullptr) {
     228              :         myRerouteCommand->deschedule();
     229       216384 :         myRerouteCommand = nullptr;
     230              :     }
     231       935134 :     if (myPeriod > 0) {
     232        41243 :         myRerouteCommand = new WrappingCommand<MSDevice_Routing>(this, &MSDevice_Routing::wrappedRerouteCommandExecute);
     233        41243 :         SUMOTime start = MSNet::getInstance()->getCurrentTimeStep();
     234        82486 :         if (OptionsCont::getOptions().getBool("device.rerouting.synchronize")) {
     235          302 :             start -= start % myPeriod;
     236              :         }
     237        41243 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myRerouteCommand, myPeriod + start);
     238              :     }
     239       935134 : }
     240              : 
     241              : 
     242              : SUMOTime
     243     15151977 : MSDevice_Routing::preInsertionReroute(const SUMOTime currentTime) {
     244     15151977 :     if (mySkipRouting == currentTime) {
     245     13063587 :         return DELTA_T;
     246              :     }
     247      2088390 :     if (myPreInsertionPeriod == 0) {
     248              :         // the event will deschedule and destroy itself so it does not need to be stored
     249          496 :         myRerouteCommand = nullptr;
     250              :     }
     251      2088390 :     const MSEdge* source = *myHolder.getRoute().begin();
     252      2088390 :     const MSEdge* dest = myHolder.getRoute().getLastEdge();
     253      2088390 :     if (source->isTazConnector() && dest->isTazConnector()) {
     254       566045 :         ConstMSRoutePtr cached = MSRoutingEngine::getCachedRoute(std::make_pair(source, dest));
     255       566045 :         if (cached != nullptr && cached->size() > 2) {
     256            0 :             myHolder.replaceRoute(cached, "device.rerouting", true);
     257            0 :             return myPreInsertionPeriod;
     258              :         }
     259              :     }
     260              :     try {
     261              :         std::string msg;
     262      2088390 :         if (myHolder.hasValidRouteStart(msg)) {
     263      2088369 :             reroute(currentTime, true);
     264              :         }
     265           97 :     } catch (ProcessError&) {
     266           97 :         myRerouteCommand = nullptr;
     267           97 :         throw;
     268           97 :     }
     269              :     // avoid repeated pre-insertion rerouting when the departure edge is fix and
     270              :     // the departure lane does not depend on the route
     271      2088293 :     if (myPreInsertionPeriod > 0 && !source->isTazConnector() && myHolder.getParameter().departLaneProcedure != DepartLaneDefinition::BEST_FREE) {
     272      1035871 :         myRerouteCommand = nullptr;
     273      1035871 :         return 0;
     274              :     }
     275      1052422 :     return myPreInsertionPeriod;
     276              : }
     277              : 
     278              : 
     279              : SUMOTime
     280       127984 : MSDevice_Routing::wrappedRerouteCommandExecute(SUMOTime currentTime) {
     281       127984 :     if (myHolder.isStopped()) {
     282        14090 :         myRerouteAfterStop = true;
     283              :     } else {
     284       113894 :         reroute(currentTime);
     285              :     }
     286       127984 :     return myPeriod;
     287              : }
     288              : 
     289              : 
     290              : void
     291      2202263 : MSDevice_Routing::reroute(const SUMOTime currentTime, const bool onInit) {
     292      2202263 :     MSRoutingEngine::initEdgeWeights(myHolder.getVClass());
     293              :     //check whether the weights did change since the last reroute
     294      2202263 :     if (myLastRouting >= MSRoutingEngine::getLastAdaptation() || !myActive) {
     295              :         return;
     296              :     }
     297      2200633 :     myLastRouting = currentTime;
     298      4401266 :     MSRoutingEngine::reroute(myHolder, currentTime, "device.rerouting", onInit);
     299              : }
     300              : 
     301              : 
     302              : std::string
     303           36 : MSDevice_Routing::getParameter(const std::string& key) const {
     304           72 :     if (StringUtils::startsWith(key, "edge:")) {
     305           18 :         const std::string edgeID = key.substr(5);
     306           18 :         const MSEdge* edge = MSEdge::dictionary(edgeID);
     307           18 :         if (edge == nullptr) {
     308            0 :             throw InvalidArgument("Edge '" + edgeID + "' is invalid for parameter retrieval of '" + deviceName() + "'");
     309              :         }
     310           18 :         return toString(MSRoutingEngine::getEffort(edge, &myHolder, 0));
     311           18 :     } else if (key == "period") {
     312           18 :         return time2string(myPeriod);
     313              :     }
     314            0 :     throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     315              : }
     316              : 
     317              : 
     318              : void
     319           33 : MSDevice_Routing::setParameter(const std::string& key, const std::string& value) {
     320              :     double doubleValue;
     321              :     try {
     322           33 :         doubleValue = StringUtils::toDouble(value);
     323            0 :     } catch (NumberFormatException&) {
     324            0 :         throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
     325            0 :     }
     326           66 :     if (StringUtils::startsWith(key, "edge:")) {
     327            9 :         const std::string edgeID = key.substr(5);
     328            9 :         const MSEdge* edge = MSEdge::dictionary(edgeID);
     329            9 :         if (edge == nullptr) {
     330            0 :             throw InvalidArgument("Edge '" + edgeID + "' is invalid for parameter setting of '" + deviceName() + "'");
     331              :         }
     332            9 :         MSRoutingEngine::setEdgeTravelTime(edge, doubleValue);
     333           24 :     } else if (key == "period") {
     334           24 :         myPeriod = TIME2STEPS(doubleValue);
     335              :         // re-schedule routing command
     336           24 :         rebuildRerouteCommand();
     337              :     } else {
     338            0 :         throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     339              :     }
     340           33 : }
     341              : 
     342              : 
     343              : void
     344         1936 : MSDevice_Routing::saveState(OutputDevice& out) const {
     345         1936 :     out.openTag(SUMO_TAG_DEVICE);
     346              :     out.writeAttr(SUMO_ATTR_ID, getID());
     347              :     std::vector<std::string> internals;
     348         1936 :     internals.push_back(toString(myPeriod));
     349         1936 :     out.writeAttr(SUMO_ATTR_STATE, toString(internals));
     350         1936 :     out.closeTag();
     351         1936 : }
     352              : 
     353              : 
     354              : void
     355         3807 : MSDevice_Routing::loadState(const SUMOSAXAttributes& attrs) {
     356         3807 :     std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
     357         3807 :     bis >> myPeriod;
     358         3807 :     if (myHolder.hasDeparted()) {
     359         1355 :         rebuildRerouteCommand();
     360              :     }
     361         3807 : }
     362              : 
     363              : 
     364              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1