LCOV - code coverage report
Current view: top level - src/microsim/devices - MSDevice_Routing.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 156 174 89.7 %
Date: 2024-04-30 15:40:33 Functions: 15 16 93.8 %

          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/StaticCommand.h>
      36             : #include <utils/common/StringUtils.h>
      37             : #include <utils/xml/SUMOSAXAttributes.h>
      38             : #include "MSRoutingEngine.h"
      39             : #include "MSDevice_Routing.h"
      40             : 
      41             : 
      42             : // ===========================================================================
      43             : // method definitions
      44             : // ===========================================================================
      45             : // ---------------------------------------------------------------------------
      46             : // static initialisation methods
      47             : // ---------------------------------------------------------------------------
      48             : void
      49       36322 : MSDevice_Routing::insertOptions(OptionsCont& oc) {
      50       72644 :     insertDefaultAssignmentOptions("rerouting", "Routing", oc);
      51             : 
      52       72644 :     oc.doRegister("device.rerouting.period", new Option_String("0", "TIME"));
      53       72644 :     oc.addSynonyme("device.rerouting.period", "device.routing.period", true);
      54       72644 :     oc.addDescription("device.rerouting.period", "Routing", TL("The period with which the vehicle shall be rerouted"));
      55             : 
      56       72644 :     oc.doRegister("device.rerouting.pre-period", new Option_String("60", "TIME"));
      57       72644 :     oc.addSynonyme("device.rerouting.pre-period", "device.routing.pre-period", true);
      58       72644 :     oc.addDescription("device.rerouting.pre-period", "Routing", TL("The rerouting period before depart"));
      59             : 
      60       36322 :     oc.doRegister("device.rerouting.adaptation-weight", new Option_Float(0));
      61       72644 :     oc.addSynonyme("device.rerouting.adaptation-weight", "device.routing.adaptation-weight", true);
      62       72644 :     oc.addDescription("device.rerouting.adaptation-weight", "Routing", TL("The weight of prior edge weights for exponential moving average"));
      63             : 
      64       36322 :     oc.doRegister("device.rerouting.adaptation-steps", new Option_Integer(180));
      65       72644 :     oc.addSynonyme("device.rerouting.adaptation-steps", "device.routing.adaptation-steps", true);
      66       72644 :     oc.addDescription("device.rerouting.adaptation-steps", "Routing", TL("The number of steps for moving average weight of prior edge weights"));
      67             : 
      68       72644 :     oc.doRegister("device.rerouting.adaptation-interval", new Option_String("1", "TIME"));
      69       72644 :     oc.addSynonyme("device.rerouting.adaptation-interval", "device.routing.adaptation-interval", true);
      70       72644 :     oc.addDescription("device.rerouting.adaptation-interval", "Routing", TL("The interval for updating the edge weights"));
      71             : 
      72       36322 :     oc.doRegister("device.rerouting.with-taz", new Option_Bool(false));
      73       72644 :     oc.addSynonyme("device.rerouting.with-taz", "device.routing.with-taz", true);
      74       72644 :     oc.addSynonyme("device.rerouting.with-taz", "with-taz");
      75       72644 :     oc.addDescription("device.rerouting.with-taz", "Routing", TL("Use zones (districts) as routing start- and endpoints"));
      76             : 
      77       72644 :     oc.doRegister("device.rerouting.mode", new Option_String("0"));
      78       72644 :     oc.addDescription("device.rerouting.mode", "Routing", TL("Set routing flags (8 ignores temporary blockages)"));
      79             : 
      80       36322 :     oc.doRegister("device.rerouting.init-with-loaded-weights", new Option_Bool(false));
      81       72644 :     oc.addDescription("device.rerouting.init-with-loaded-weights", "Routing", TL("Use weight files given with option --weight-files for initializing edge weights"));
      82             : 
      83       36322 :     oc.doRegister("device.rerouting.threads", new Option_Integer(0));
      84       72644 :     oc.addSynonyme("device.rerouting.threads", "routing-threads");
      85       72644 :     oc.addDescription("device.rerouting.threads", "Routing", TL("The number of parallel execution threads used for rerouting"));
      86             : 
      87       36322 :     oc.doRegister("device.rerouting.synchronize", new Option_Bool(false));
      88       72644 :     oc.addDescription("device.rerouting.synchronize", "Routing", TL("Let rerouting happen at the same time for all vehicles"));
      89             : 
      90       36322 :     oc.doRegister("device.rerouting.railsignal", new Option_Bool(true));
      91       72644 :     oc.addDescription("device.rerouting.railsignal", "Routing", TL("Allow rerouting triggered by rail signals."));
      92             : 
      93       36322 :     oc.doRegister("device.rerouting.bike-speeds", new Option_Bool(false));
      94       72644 :     oc.addDescription("device.rerouting.bike-speeds", "Routing", TL("Compute separate average speeds for bicycles"));
      95             : 
      96       72644 :     oc.doRegister("device.rerouting.output", new Option_FileName());
      97       72644 :     oc.addDescription("device.rerouting.output", "Routing", TL("Save adapting weights to FILE"));
      98       36322 : }
      99             : 
     100             : 
     101             : bool
     102       35752 : MSDevice_Routing::checkOptions(OptionsCont& oc) {
     103             :     bool ok = true;
     104       71804 :     if (!oc.isDefault("device.rerouting.adaptation-steps") && !oc.isDefault("device.rerouting.adaptation-weight")) {
     105           0 :         WRITE_ERROR(TL("Only one of the options 'device.rerouting.adaptation-steps' or 'device.rerouting.adaptation-weight' may be given."));
     106             :         ok = false;
     107             :     }
     108       71504 :     if (oc.getFloat("weights.random-factor") < 1) {
     109           0 :         WRITE_ERROR(TL("weights.random-factor cannot be less than 1"));
     110             :         ok = false;
     111             :     }
     112      107256 :     if (string2time(oc.getString("device.rerouting.adaptation-interval")) < 0) {
     113          14 :         WRITE_ERROR(TL("Negative value for device.rerouting.adaptation-interval!"));
     114             :         ok = false;
     115             :     }
     116      107256 :     if (oc.getFloat("device.rerouting.adaptation-weight") < 0.  ||
     117      107256 :             oc.getFloat("device.rerouting.adaptation-weight") > 1.) {
     118           0 :         WRITE_ERROR(TL("The value for device.rerouting.adaptation-weight must be between 0 and 1!"));
     119             :         ok = false;
     120             :     }
     121             : #ifndef HAVE_FOX
     122             :     if (oc.getInt("device.rerouting.threads") > 1) {
     123             :         WRITE_ERROR(TL("Parallel routing is only possible when compiled with Fox."));
     124             :         ok = false;
     125             :     }
     126             : #endif
     127       39607 :     if (oc.getInt("threads") > 1 && oc.getInt("device.rerouting.threads") > 1 && oc.getInt("threads") != oc.getInt("device.rerouting.threads")) {
     128          16 :         WRITE_WARNING(TL("Adapting number of routing threads to number of simulation threads."));
     129             :     }
     130       35752 :     return ok;
     131             : }
     132             : 
     133             : 
     134             : void
     135     4655793 : MSDevice_Routing::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
     136     4655793 :     const OptionsCont& oc = OptionsCont::getOptions();
     137     4655793 :     const bool equip = equippedByDefaultAssignmentOptions(oc, "rerouting", v, false);
     138     4655787 :     if (v.getParameter().wasSet(VEHPARS_FORCE_REROUTE) || equip) {
     139             :         // route computation is enabled
     140             :         // for implicitly equipped vehicles (trips, flows), option probability
     141             :         // can still be used to disable periodic rerouting after insertion for
     142             :         // parts of the fleet
     143     2781180 :         const SUMOTime period = equip || oc.isDefault("device.rerouting.probability") ? getTimeParam(v, oc, "rerouting.period", 0, false) : 0;
     144     2781250 :         const SUMOTime prePeriod = MAX2((SUMOTime)0, getTimeParam(v, oc, "rerouting.pre-period", string2time(oc.getString("device.rerouting.pre-period")), false));
     145     1390625 :         MSRoutingEngine::initWeightUpdate();
     146             :         // build the device
     147     2143097 :         into.push_back(new MSDevice_Routing(v, "routing_" + v.getID(), period, prePeriod));
     148             :     }
     149     4655787 : }
     150             : 
     151             : 
     152             : // ---------------------------------------------------------------------------
     153             : // MSDevice_Routing-methods
     154             : // ---------------------------------------------------------------------------
     155     1390625 : MSDevice_Routing::MSDevice_Routing(SUMOVehicle& holder, const std::string& id,
     156     1390625 :                                    SUMOTime period, SUMOTime preInsertionPeriod) :
     157             :     MSVehicleDevice(holder, id),
     158     1390625 :     myPeriod(period),
     159     1390625 :     myPreInsertionPeriod(preInsertionPeriod),
     160     1390625 :     myLastRouting(-1),
     161     1390625 :     mySkipRouting(-1),
     162     1390625 :     myRerouteCommand(nullptr),
     163     1390625 :     myRerouteRailSignal(getBoolParam(holder, OptionsCont::getOptions(), "rerouting.railsignal", true, true)),
     164     1390625 :     myLastLaneEntryTime(-1),
     165     1390625 :     myRerouteAfterStop(false),
     166     1390625 :     myActive(true) {
     167     1390625 :     if (myPreInsertionPeriod > 0 || holder.getParameter().wasSet(VEHPARS_FORCE_REROUTE)) {
     168             :         // 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")
     169     1389815 :         myRerouteCommand = new WrappingCommand<MSDevice_Routing>(this, &MSDevice_Routing::preInsertionReroute);
     170             :         // if we don't update the edge weights, we might as well reroute now and hopefully use our threads better
     171     1389815 :         const SUMOTime execTime = MSRoutingEngine::hasEdgeUpdates() ? holder.getParameter().depart : -1;
     172     1389815 :         MSNet::getInstance()->getInsertionEvents()->addEvent(myRerouteCommand, execTime);
     173             :     }
     174     1390625 : }
     175             : 
     176             : 
     177     2781234 : MSDevice_Routing::~MSDevice_Routing() {
     178             :     // make the rerouting command invalid if there is one
     179     1390617 :     if (myRerouteCommand != nullptr) {
     180             :         myRerouteCommand->deschedule();
     181             :     }
     182     2781234 : }
     183             : 
     184             : 
     185             : bool
     186     1366122 : MSDevice_Routing::notifyEnter(SUMOTrafficObject& /*veh*/, MSMoveReminder::Notification reason, const MSLane* enteredLane) {
     187     1366122 :     if (reason == MSMoveReminder::NOTIFICATION_DEPARTED) {
     188     1333987 :         if (myRerouteCommand == nullptr && myPreInsertionPeriod > 0 && myHolder.getDepartDelay() > myPreInsertionPeriod) {
     189             :             // pre-insertion rerouting was disabled. Reroute once if insertion was delayed
     190             :             // this is happening in the run thread (not inbeginOfTimestepEvents) so we cannot safely use the threadPool
     191     2060028 :             myHolder.reroute(MSNet::getInstance()->getCurrentTimeStep(), "device.rerouting",
     192     1373352 :                              MSRoutingEngine::getRouterTT(myHolder.getRNGIndex(), myHolder.getVClass()),
     193             :                              false, MSRoutingEngine::withTaz(), false);
     194             :         }
     195             :         // build repetition trigger if routing shall be done more often
     196     1333987 :         rebuildRerouteCommand();
     197             :     }
     198     1366122 :     if (MSGlobals::gWeightsSeparateTurns > 0) {
     199       35980 :         if (reason == MSMoveReminder::NOTIFICATION_JUNCTION) {
     200       30980 :             const SUMOTime t = SIMSTEP;
     201       30980 :             if (myLastLaneEntryTime >= 0 && enteredLane->isInternal()) {
     202             :                 // record travel time on the previous edge but store on the internal ledge
     203       10980 :                 MSRoutingEngine::addEdgeTravelTime(enteredLane->getEdge(), t - myLastLaneEntryTime);
     204             :             }
     205       30980 :             myLastLaneEntryTime = t;
     206             :         }
     207       35980 :         return true;
     208             :     } else {
     209             :         return false;
     210             :     }
     211             : }
     212             : 
     213             : 
     214             : void
     215           0 : MSDevice_Routing::notifyStopEnded() {
     216           0 :     if (myRerouteAfterStop) {
     217           0 :         reroute(SIMSTEP);
     218           0 :         myRerouteAfterStop = false;
     219             :     }
     220           0 : }
     221             : 
     222             : 
     223             : void
     224     1334015 : MSDevice_Routing::rebuildRerouteCommand() {
     225     1334015 :     if (myRerouteCommand != nullptr) {
     226             :         myRerouteCommand->deschedule();
     227      350575 :         myRerouteCommand = nullptr;
     228             :     }
     229     1334015 :     if (myPeriod > 0) {
     230       33315 :         myRerouteCommand = new WrappingCommand<MSDevice_Routing>(this, &MSDevice_Routing::wrappedRerouteCommandExecute);
     231       33315 :         SUMOTime start = MSNet::getInstance()->getCurrentTimeStep();
     232       66630 :         if (OptionsCont::getOptions().getBool("device.rerouting.synchronize")) {
     233           0 :             start -= start % myPeriod;
     234             :         }
     235       33315 :         MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(myRerouteCommand, myPeriod + start);
     236             :     }
     237     1334015 : }
     238             : 
     239             : 
     240             : SUMOTime
     241    15132548 : MSDevice_Routing::preInsertionReroute(const SUMOTime currentTime) {
     242    15132548 :     if (mySkipRouting == currentTime) {
     243    13147639 :         return DELTA_T;
     244             :     }
     245     1984909 :     if (myPreInsertionPeriod == 0) {
     246             :         // the event will deschedule and destroy itself so it does not need to be stored
     247         496 :         myRerouteCommand = nullptr;
     248             :     }
     249     1984909 :     const MSEdge* source = *myHolder.getRoute().begin();
     250     1984909 :     const MSEdge* dest = myHolder.getRoute().getLastEdge();
     251     1984909 :     if (source->isTazConnector() && dest->isTazConnector()) {
     252      675361 :         ConstMSRoutePtr cached = MSRoutingEngine::getCachedRoute(std::make_pair(source, dest));
     253      675361 :         if (cached != nullptr && cached->size() > 2) {
     254           0 :             myHolder.replaceRoute(cached, "device.rerouting", true);
     255           0 :             return myPreInsertionPeriod;
     256             :         }
     257             :     }
     258             :     try {
     259             :         std::string msg;
     260     1984909 :         if (myHolder.hasValidRouteStart(msg)) {
     261     1984888 :             reroute(currentTime, true);
     262             :         }
     263          96 :     } catch (ProcessError&) {
     264          96 :         myRerouteCommand = nullptr;
     265          96 :         throw;
     266          96 :     }
     267             :     // avoid repeated pre-insertion rerouting when the departure edge is fix and
     268             :     // the departure lane does not depend on the route
     269     1984813 :     if (myPreInsertionPeriod > 0 && !source->isTazConnector() && myHolder.getParameter().departLaneProcedure != DepartLaneDefinition::BEST_FREE) {
     270     1010485 :         myRerouteCommand = nullptr;
     271     1010485 :         return 0;
     272             :     }
     273      974328 :     return myPreInsertionPeriod;
     274             : }
     275             : 
     276             : 
     277             : SUMOTime
     278      124996 : MSDevice_Routing::wrappedRerouteCommandExecute(SUMOTime currentTime) {
     279      124996 :     if (myHolder.isStopped()) {
     280        8512 :         myRerouteAfterStop = true;
     281             :     } else {
     282      116484 :         reroute(currentTime);
     283             :     }
     284      124996 :     return myPeriod;
     285             : }
     286             : 
     287             : 
     288             : void
     289     2101372 : MSDevice_Routing::reroute(const SUMOTime currentTime, const bool onInit) {
     290     2101372 :     MSRoutingEngine::initEdgeWeights(myHolder.getVClass());
     291             :     //check whether the weights did change since the last reroute
     292     2101372 :     if (myLastRouting >= MSRoutingEngine::getLastAdaptation() || !myActive) {
     293             :         return;
     294             :     }
     295     2099670 :     myLastRouting = currentTime;
     296     4199340 :     MSRoutingEngine::reroute(myHolder, currentTime, "device.rerouting", onInit);
     297             : }
     298             : 
     299             : 
     300             : std::string
     301          40 : MSDevice_Routing::getParameter(const std::string& key) const {
     302          80 :     if (StringUtils::startsWith(key, "edge:")) {
     303          20 :         const std::string edgeID = key.substr(5);
     304          20 :         const MSEdge* edge = MSEdge::dictionary(edgeID);
     305          20 :         if (edge == nullptr) {
     306           0 :             throw InvalidArgument("Edge '" + edgeID + "' is invalid for parameter retrieval of '" + deviceName() + "'");
     307             :         }
     308          20 :         return toString(MSRoutingEngine::getEffort(edge, &myHolder, 0));
     309          20 :     } else if (key == "period") {
     310          20 :         return time2string(myPeriod);
     311             :     }
     312           0 :     throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     313             : }
     314             : 
     315             : 
     316             : void
     317          38 : MSDevice_Routing::setParameter(const std::string& key, const std::string& value) {
     318             :     double doubleValue;
     319             :     try {
     320          38 :         doubleValue = StringUtils::toDouble(value);
     321           0 :     } catch (NumberFormatException&) {
     322           0 :         throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
     323           0 :     }
     324          76 :     if (StringUtils::startsWith(key, "edge:")) {
     325          10 :         const std::string edgeID = key.substr(5);
     326          10 :         const MSEdge* edge = MSEdge::dictionary(edgeID);
     327          10 :         if (edge == nullptr) {
     328           0 :             throw InvalidArgument("Edge '" + edgeID + "' is invalid for parameter setting of '" + deviceName() + "'");
     329             :         }
     330          10 :         MSRoutingEngine::setEdgeTravelTime(edge, doubleValue);
     331          28 :     } else if (key == "period") {
     332          28 :         myPeriod = TIME2STEPS(doubleValue);
     333             :         // re-schedule routing command
     334          28 :         rebuildRerouteCommand();
     335             :     } else {
     336           0 :         throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
     337             :     }
     338          38 : }
     339             : 
     340             : 
     341             : void
     342        1462 : MSDevice_Routing::saveState(OutputDevice& out) const {
     343        1462 :     out.openTag(SUMO_TAG_DEVICE);
     344             :     out.writeAttr(SUMO_ATTR_ID, getID());
     345             :     std::vector<std::string> internals;
     346        1462 :     internals.push_back(toString(myPeriod));
     347        1462 :     out.writeAttr(SUMO_ATTR_STATE, toString(internals));
     348        1462 :     out.closeTag();
     349        1462 : }
     350             : 
     351             : 
     352             : void
     353        3904 : MSDevice_Routing::loadState(const SUMOSAXAttributes& attrs) {
     354        3904 :     std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
     355        3904 :     bis >> myPeriod;
     356        3904 : }
     357             : 
     358             : 
     359             : /****************************************************************************/

Generated by: LCOV version 1.14