Eclipse SUMO - Simulation of Urban MObility
MSDevice_Routing.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2007-2020 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 /****************************************************************************/
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>
31 #include <microsim/MSGlobals.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
50  insertDefaultAssignmentOptions("rerouting", "Routing", oc);
51 
52  oc.doRegister("device.rerouting.period", new Option_String("0", "TIME"));
53  oc.addSynonyme("device.rerouting.period", "device.routing.period", true);
54  oc.addDescription("device.rerouting.period", "Routing", "The period with which the vehicle shall be rerouted");
55 
56  oc.doRegister("device.rerouting.pre-period", new Option_String("60", "TIME"));
57  oc.addSynonyme("device.rerouting.pre-period", "device.routing.pre-period", true);
58  oc.addDescription("device.rerouting.pre-period", "Routing", "The rerouting period before depart");
59 
60  oc.doRegister("device.rerouting.adaptation-weight", new Option_Float(0));
61  oc.addSynonyme("device.rerouting.adaptation-weight", "device.routing.adaptation-weight", true);
62  oc.addDescription("device.rerouting.adaptation-weight", "Routing", "The weight of prior edge weights for exponential moving average");
63 
64  oc.doRegister("device.rerouting.adaptation-steps", new Option_Integer(180));
65  oc.addSynonyme("device.rerouting.adaptation-steps", "device.routing.adaptation-steps", true);
66  oc.addDescription("device.rerouting.adaptation-steps", "Routing", "The number of steps for moving average weight of prior edge weights");
67 
68  oc.doRegister("device.rerouting.adaptation-interval", new Option_String("1", "TIME"));
69  oc.addSynonyme("device.rerouting.adaptation-interval", "device.routing.adaptation-interval", true);
70  oc.addDescription("device.rerouting.adaptation-interval", "Routing", "The interval for updating the edge weights");
71 
72  oc.doRegister("device.rerouting.with-taz", new Option_Bool(false));
73  oc.addSynonyme("device.rerouting.with-taz", "device.routing.with-taz", true);
74  oc.addSynonyme("device.rerouting.with-taz", "with-taz");
75  oc.addDescription("device.rerouting.with-taz", "Routing", "Use zones (districts) as routing start- and endpoints");
76 
77  oc.doRegister("device.rerouting.init-with-loaded-weights", new Option_Bool(false));
78  oc.addDescription("device.rerouting.init-with-loaded-weights", "Routing", "Use weight files given with option --weight-files for initializing edge weights");
79 
80  oc.doRegister("device.rerouting.threads", new Option_Integer(0));
81  oc.addDescription("device.rerouting.threads", "Routing", "The number of parallel execution threads used for rerouting");
82 
83  oc.doRegister("device.rerouting.synchronize", new Option_Bool(false));
84  oc.addDescription("device.rerouting.synchronize", "Routing", "Let rerouting happen at the same time for all vehicles");
85 
86  oc.doRegister("device.rerouting.railsignal", new Option_Bool(true));
87  oc.addDescription("device.rerouting.railsignal", "Routing", "Allow rerouting triggered by rail signals.");
88 
89  oc.doRegister("device.rerouting.bike-speeds", new Option_Bool(false));
90  oc.addDescription("device.rerouting.bike-speeds", "Routing", "Compute separate average speeds for bicycles");
91 
92  oc.doRegister("device.rerouting.output", new Option_FileName());
93  oc.addDescription("device.rerouting.output", "Routing", "Save adapting weights to FILE");
94 }
95 
96 
97 bool
99  bool ok = true;
100  if (!oc.isDefault("device.rerouting.adaptation-steps") && !oc.isDefault("device.rerouting.adaptation-weight")) {
101  WRITE_ERROR("Only one of the options 'device.rerouting.adaptation-steps' or 'device.rerouting.adaptation-weight' may be given.");
102  ok = false;
103  }
104  if (oc.getFloat("weights.random-factor") < 1) {
105  WRITE_ERROR("weights.random-factor cannot be less than 1");
106  ok = false;
107  }
108  if (string2time(oc.getString("device.rerouting.adaptation-interval")) < 0) {
109  WRITE_ERROR("Negative value for device.rerouting.adaptation-interval!");
110  ok = false;
111  }
112  if (oc.getFloat("device.rerouting.adaptation-weight") < 0. ||
113  oc.getFloat("device.rerouting.adaptation-weight") > 1.) {
114  WRITE_ERROR("The value for device.rerouting.adaptation-weight must be between 0 and 1!");
115  ok = false;
116  }
117 #ifndef HAVE_FOX
118  if (oc.getInt("device.rerouting.threads") > 1) {
119  WRITE_ERROR("Parallel routing is only possible when compiled with Fox.");
120  ok = false;
121  }
122 #endif
123  if (oc.getInt("threads") > 1 && oc.getInt("device.rerouting.threads") > 1 && oc.getInt("threads") != oc.getInt("device.rerouting.threads")) {
124  WRITE_WARNING("Adapting number of routing threads to number of simulation threads.");
125  }
126  return ok;
127 }
128 
129 
130 void
131 MSDevice_Routing::buildVehicleDevices(SUMOVehicle& v, std::vector<MSVehicleDevice*>& into) {
132  const OptionsCont& oc = OptionsCont::getOptions();
133  const bool equip = equippedByDefaultAssignmentOptions(oc, "rerouting", v, false);
134  if (v.getParameter().wasSet(VEHPARS_FORCE_REROUTE) || equip) {
135  // route computation is enabled
136  // for implicitly equipped vehicles (trips, flows), option probability
137  // can still be used to disable periodic rerouting after insertion for
138  // parts of the fleet
139  const SUMOTime period = equip || oc.isDefault("device.rerouting.probability") ? string2time(oc.getString("device.rerouting.period")) : 0;
140  const SUMOTime prePeriod = MAX2((SUMOTime)0, string2time(oc.getString("device.rerouting.pre-period")));
142  // build the device
143  into.push_back(new MSDevice_Routing(v, "routing_" + v.getID(), period, prePeriod));
144  }
145 }
146 
147 
148 // ---------------------------------------------------------------------------
149 // MSDevice_Routing-methods
150 // ---------------------------------------------------------------------------
151 MSDevice_Routing::MSDevice_Routing(SUMOVehicle& holder, const std::string& id,
152  SUMOTime period, SUMOTime preInsertionPeriod) :
153  MSVehicleDevice(holder, id),
154  myPeriod(period),
155  myPreInsertionPeriod(preInsertionPeriod),
156  myLastRouting(-1),
157  mySkipRouting(-1),
158  myRerouteCommand(nullptr),
159  myRerouteRailSignal(getBoolParam(holder, OptionsCont::getOptions(), "rerouting.railsignal", true, true)) {
161  // 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")
163  // if we don't update the edge weights, we might as well reroute now and hopefully use our threads better
164  const SUMOTime execTime = MSRoutingEngine::hasEdgeUpdates() ? holder.getParameter().depart : -1;
166  }
167 }
168 
169 
171  // make the rerouting command invalid if there is one
172  if (myRerouteCommand != nullptr) {
174  }
175 }
176 
177 
178 bool
181  // clean up pre depart rerouting
182  if (myRerouteCommand != nullptr) {
184  } else if (myPreInsertionPeriod > 0 && myHolder.getDepartDelay() > myPreInsertionPeriod && enteredLane != nullptr) {
185  // pre-insertion rerouting was disabled. Reroute once if insertion was delayed
186  // this is happening in the run thread (not inbeginOfTimestepEvents) so we cannot safely use the threadPool
187  myHolder.reroute(MSNet::getInstance()->getCurrentTimeStep(), "device.rerouting",
189  false, MSRoutingEngine::withTaz(), false);
190  }
191  myRerouteCommand = nullptr;
192  // build repetition trigger if routing shall be done more often
193  if (myPeriod > 0) {
196  if (OptionsCont::getOptions().getBool("device.rerouting.synchronize")) {
197  start -= start % myPeriod;
198  }
200  }
201  }
202  return false;
203 }
204 
205 
206 SUMOTime
208  if (mySkipRouting == currentTime) {
209  return DELTA_T;
210  }
211  if (myPreInsertionPeriod == 0) {
212  // the event will deschedule and destroy itself so it does not need to be stored
213  myRerouteCommand = nullptr;
214  }
215  const MSEdge* source = *myHolder.getRoute().begin();
216  const MSEdge* dest = myHolder.getRoute().getLastEdge();
217  if (source->isTazConnector() && dest->isTazConnector()) {
218  const MSRoute* cached = MSRoutingEngine::getCachedRoute(std::make_pair(source, dest));
219  if (cached != nullptr && cached->size() > 2) {
220  myHolder.replaceRoute(cached, "device.rerouting", true);
221  return myPreInsertionPeriod;
222  }
223  }
224  try {
225  std::string msg;
226  if (myHolder.hasValidRouteStart(msg)) {
227  reroute(currentTime, true);
228  }
229  } catch (ProcessError&) {
230  myRerouteCommand = nullptr;
231  throw;
232  }
233  // avoid repeated pre-insertion rerouting when the departure edge is fix and
234  // the departure lane does not depend on the route
236  myRerouteCommand = nullptr;
237  return 0;
238  }
239  return myPreInsertionPeriod;
240 }
241 
242 
243 SUMOTime
245  reroute(currentTime);
246  return myPeriod;
247 }
248 
249 
250 void
251 MSDevice_Routing::reroute(const SUMOTime currentTime, const bool onInit) {
253  //check whether the weights did change since the last reroute
255  return;
256  }
257  myLastRouting = currentTime;
258  MSRoutingEngine::reroute(myHolder, currentTime, "device.rerouting", onInit);
259 }
260 
261 
262 std::string
263 MSDevice_Routing::getParameter(const std::string& key) const {
264  if (StringUtils::startsWith(key, "edge:")) {
265  const std::string edgeID = key.substr(5);
266  const MSEdge* edge = MSEdge::dictionary(edgeID);
267  if (edge == nullptr) {
268  throw InvalidArgument("Edge '" + edgeID + "' is invalid for parameter retrieval of '" + deviceName() + "'");
269  }
270  return toString(MSRoutingEngine::getEffort(edge, &myHolder, 0));
271  } else if (key == "period") {
272  return time2string(myPeriod);
273  }
274  throw InvalidArgument("Parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
275 }
276 
277 
278 void
279 MSDevice_Routing::setParameter(const std::string& key, const std::string& value) {
280  double doubleValue;
281  try {
282  doubleValue = StringUtils::toDouble(value);
283  } catch (NumberFormatException&) {
284  throw InvalidArgument("Setting parameter '" + key + "' requires a number for device of type '" + deviceName() + "'");
285  }
286  if (StringUtils::startsWith(key, "edge:")) {
287  const std::string edgeID = key.substr(5);
288  const MSEdge* edge = MSEdge::dictionary(edgeID);
289  if (edge == nullptr) {
290  throw InvalidArgument("Edge '" + edgeID + "' is invalid for parameter setting of '" + deviceName() + "'");
291  }
292  MSRoutingEngine::setEdgeTravelTime(edge, doubleValue);
293  } else if (key == "period") {
294  myPeriod = TIME2STEPS(doubleValue);
295  // re-schedule routing command
297  } else {
298  throw InvalidArgument("Setting parameter '" + key + "' is not supported for device of type '" + deviceName() + "'");
299  }
300 }
301 
302 
303 void
306  out.writeAttr(SUMO_ATTR_ID, getID());
307  std::vector<std::string> internals;
308  internals.push_back(toString(myPeriod));
309  out.writeAttr(SUMO_ATTR_STATE, toString(internals));
310  out.closeTag();
311 }
312 
313 
314 void
316  std::istringstream bis(attrs.getString(SUMO_ATTR_STATE));
317  bis >> myPeriod;
318 }
319 
320 
321 /****************************************************************************/
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:284
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:276
SUMOTime DELTA_T
Definition: SUMOTime.cpp:37
std::string time2string(SUMOTime t)
convert SUMOTime to string
Definition: SUMOTime.cpp:68
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition: SUMOTime.cpp:45
#define TIME2STEPS(x)
Definition: SUMOTime.h:55
long long int SUMOTime
Definition: SUMOTime.h:31
@ BEST_FREE
The least occupied lane from best lanes.
const int VEHPARS_FORCE_REROUTE
@ SUMO_TAG_DEVICE
@ SUMO_ATTR_ID
@ SUMO_ATTR_STATE
The state of a link.
T MAX2(T a, T b)
Definition: StdDefs.h:79
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:44
const std::string deviceName() const
return the name for this type of device
void saveState(OutputDevice &out) const
Saves the state of the device.
SUMOTime wrappedRerouteCommandExecute(SUMOTime currentTime)
Performs rerouting after a period.
SUMOTime mySkipRouting
The time for which routing may be skipped because we cannot be inserted.
static void insertOptions(OptionsCont &oc)
Inserts MSDevice_Routing-options.
std::string getParameter(const std::string &key) const
try to retrieve the given parameter from this device. Throw exception for unsupported key
bool notifyEnter(SUMOTrafficObject &veh, MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
Computes a new route on vehicle insertion.
SUMOTime myPreInsertionPeriod
The period with which a vehicle shall be rerouted before insertion.
SUMOTime myPeriod
The period with which a vehicle shall be rerouted.
void loadState(const SUMOSAXAttributes &attrs)
Loads the state of the device from the given description.
void reroute(const SUMOTime currentTime, const bool onInit=false)
initiate the rerouting, create router / thread pool on first use
static bool checkOptions(OptionsCont &oc)
checks MSDevice_Routing-options
MSDevice_Routing(SUMOVehicle &holder, const std::string &id, SUMOTime period, SUMOTime preInsertionPeriod)
Constructor.
WrappingCommand< MSDevice_Routing > * myRerouteCommand
The (optional) command responsible for rerouting.
~MSDevice_Routing()
Destructor.
static void buildVehicleDevices(SUMOVehicle &v, std::vector< MSVehicleDevice * > &into)
Build devices for the given vehicle, if needed.
SUMOTime myLastRouting
The last time a routing took place.
void setParameter(const std::string &key, const std::string &value)
try to set the given parameter for this device. Throw exception for unsupported key
SUMOTime preInsertionReroute(const SUMOTime currentTime)
Performs rerouting before insertion into the network.
static void insertDefaultAssignmentOptions(const std::string &deviceName, const std::string &optionsTopic, OptionsCont &oc, const bool isPerson=false)
Adds common command options that allow to assign devices to vehicles.
Definition: MSDevice.cpp:134
static bool equippedByDefaultAssignmentOptions(const OptionsCont &oc, const std::string &deviceName, DEVICEHOLDER &v, bool outputOptionSet, const bool isPerson=false)
Determines whether a vehicle should get a certain device.
Definition: MSDevice.h:204
A road/street connecting two junctions.
Definition: MSEdge.h:77
bool isTazConnector() const
Definition: MSEdge.h:279
static bool dictionary(const std::string &id, MSEdge *edge)
Inserts edge into the static dictionary Returns true if the key id isn't already in the dictionary....
Definition: MSEdge.cpp:814
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
Representation of a lane in the micro simulation.
Definition: MSLane.h:82
Notification
Definition of a vehicle state.
@ NOTIFICATION_DEPARTED
The vehicle has departed (was inserted into the network)
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:171
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:313
MSEventControl * getInsertionEvents()
Returns the event control for insertion events.
Definition: MSNet.h:484
MSEventControl * getBeginOfTimestepEvents()
Returns the event control for events executed at the begin of a time step.
Definition: MSNet.h:464
int size() const
Returns the number of edges to pass.
Definition: MSRoute.cpp:81
const MSEdge * getLastEdge() const
returns the destination edge
Definition: MSRoute.cpp:87
MSRouteIterator begin() const
Returns the begin of the list of edges to pass.
Definition: MSRoute.cpp:69
static void setEdgeTravelTime(const MSEdge *const edge, const double travelTime)
adapt the known travel time for an edge
static void reroute(SUMOVehicle &vehicle, const SUMOTime currentTime, const std::string &info, const bool onInit=false, const bool silent=false, const MSEdgeVector &prohibited=MSEdgeVector())
initiate the rerouting, create router / thread pool on first use
static SUMOTime getLastAdaptation()
Information when the last edge weight adaptation occurred.
static bool withTaz()
whether taz-routing is enabled
static const MSRoute * getCachedRoute(const std::pair< const MSEdge *, const MSEdge * > &key)
return the cached route or nullptr on miss
static bool hasEdgeUpdates()
returns whether any routing actions take place
static void initWeightUpdate()
intialize period edge weight update
static void initEdgeWeights(SUMOVehicleClass svc)
initialize the edge weights if not done before
static SUMOAbstractRouter< MSEdge, SUMOVehicle > & getRouterTT(const int rngIndex, SUMOVehicleClass svc, const MSEdgeVector &prohibited=MSEdgeVector())
return the router instance
static double getEffort(const MSEdge *const e, const SUMOVehicle *const v, double t)
Returns the effort to pass an edge.
Abstract in-vehicle device.
SUMOVehicle & myHolder
The vehicle that stores the device.
const std::string & getID() const
Returns the id.
Definition: Named.h:73
An integer-option.
Definition: Option.h:329
A storage for options typed value containers)
Definition: OptionsCont.h:89
void addDescription(const std::string &name, const std::string &subtopic, const std::string &description)
Adds a description for an option.
void doRegister(const std::string &name, Option *v)
Adds an option under the given name.
Definition: OptionsCont.cpp:75
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
void addSynonyme(const std::string &name1, const std::string &name2, bool isDeprecated=false)
Adds a synonyme for an options name (any order)
Definition: OptionsCont.cpp:96
bool isDefault(const std::string &name) const
Returns the information whether the named option has still the default value.
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:60
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:239
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
Encapsulated SAX-Attributes.
virtual std::string getString(int id) const =0
Returns the string-value of the named (by its enum-value) attribute.
Representation of a vehicle, person, or container.
virtual SUMOVehicleClass getVClass() const =0
Returns the object's access class.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle's parameter (including departure definition)
Representation of a vehicle.
Definition: SUMOVehicle.h:58
virtual const MSRoute & getRoute() const =0
Returns the current route.
virtual void reroute(SUMOTime t, const std::string &info, SUMOAbstractRouter< MSEdge, SUMOVehicle > &router, const bool onInit=false, const bool withTaz=false, const bool silent=false)=0
Performs a rerouting using the given router.
virtual bool replaceRoute(const MSRoute *route, const std::string &info, bool onInit=false, int offset=0, bool addStops=true, bool removeStops=true)=0
Replaces the current route by the given one.
virtual int getRNGIndex() const =0
virtual bool hasValidRouteStart(std::string &msg)=0
checks wether the vehicle can depart on the first edge
virtual SUMOTime getDepartDelay() const =0
DepartLaneDefinition departLaneProcedure
Information how the vehicle shall choose the lane to depart from.
bool wasSet(int what) const
Returns whether the given parameter was set.
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
void deschedule()
Marks this Command as being descheduled.