SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MSDevice_Routing.cpp
Go to the documentation of this file.
1 /****************************************************************************/
11 // A device that performs vehicle rerouting based on current edge speeds
12 /****************************************************************************/
13 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
14 // Copyright (C) 2007-2014 DLR (http://www.dlr.de/) and contributors
15 /****************************************************************************/
16 //
17 // This file is part of SUMO.
18 // SUMO is free software: you can redistribute it and/or modify
19 // it under the terms of the GNU General Public License as published by
20 // the Free Software Foundation, either version 3 of the License, or
21 // (at your option) any later version.
22 //
23 /****************************************************************************/
24 
25 // ===========================================================================
26 // included modules
27 // ===========================================================================
28 #ifdef _MSC_VER
29 #include <windows_config.h>
30 #else
31 #include <config.h>
32 #endif
33 
34 #include "MSDevice_Routing.h"
35 #include <microsim/MSNet.h>
36 #include <microsim/MSLane.h>
37 #include <microsim/MSEdge.h>
38 #include <microsim/MSEdgeControl.h>
39 #include <microsim/MSGlobals.h>
46 #include <utils/vehicle/CHRouter.h>
48 
49 #ifdef CHECK_MEMORY_LEAKS
50 #include <foreign/nvwa/debug_new.h>
51 #endif // CHECK_MEMORY_LEAKS
52 
53 
54 // ===========================================================================
55 // static member variables
56 // ===========================================================================
57 std::vector<SUMOReal> MSDevice_Routing::myEdgeEfforts;
63 std::map<std::pair<const MSEdge*, const MSEdge*>, const MSRoute*> MSDevice_Routing::myCachedRoutes;
65 #ifdef HAVE_FOX
66 FXWorkerThread::Pool MSDevice_Routing::myThreadPool;
67 #endif
68 
69 
70 // ===========================================================================
71 // method definitions
72 // ===========================================================================
73 // ---------------------------------------------------------------------------
74 // static initialisation methods
75 // ---------------------------------------------------------------------------
76 void
78  oc.addOptionSubTopic("Routing");
79  insertDefaultAssignmentOptions("rerouting", "Routing", oc);
80 
81  oc.doRegister("device.rerouting.period", new Option_String("0", "TIME"));
82  oc.addSynonyme("device.rerouting.period", "device.routing.period", true);
83  oc.addDescription("device.rerouting.period", "Routing", "The period with which the vehicle shall be rerouted");
84 
85  oc.doRegister("device.rerouting.pre-period", new Option_String("1", "TIME"));
86  oc.addSynonyme("device.rerouting.pre-period", "device.routing.pre-period", true);
87  oc.addDescription("device.rerouting.pre-period", "Routing", "The rerouting period before depart");
88 
89  oc.doRegister("device.rerouting.adaptation-weight", new Option_Float(.5));
90  oc.addSynonyme("device.rerouting.adaptation-weight", "device.routing.adaptation-weight", true);
91  oc.addDescription("device.rerouting.adaptation-weight", "Routing", "The weight of prior edge weights");
92 
93  oc.doRegister("device.rerouting.adaptation-interval", new Option_String("1", "TIME"));
94  oc.addSynonyme("device.rerouting.adaptation-interval", "device.routing.adaptation-interval", true);
95  oc.addDescription("device.rerouting.adaptation-interval", "Routing", "The interval for updating the edge weights");
96 
97  oc.doRegister("device.rerouting.with-taz", new Option_Bool(false));
98  oc.addSynonyme("device.rerouting.with-taz", "device.routing.with-taz", true);
99  oc.addDescription("device.rerouting.with-taz", "Routing", "Use zones (districts) as routing end points");
100 
101  oc.doRegister("device.rerouting.init-with-loaded-weights", new Option_Bool(false));
102  oc.addDescription("device.rerouting.init-with-loaded-weights", "Routing", "Use given weight files for initializing edge weights");
103 
104  oc.doRegister("device.rerouting.shortest-path-file", new Option_FileName());
105  oc.addDescription("device.rerouting.shortest-path-file", "Routing", "Initialize lookup table for astar from the given distance matrix");
106 
107 #ifdef HAVE_FOX
108  oc.doRegister("device.rerouting.threads", new Option_Integer(0));
109  oc.addDescription("device.rerouting.threads", "Routing", "The number of parallel execution threads used for rerouting");
110 #endif
111 
113  myEdgeEfforts.clear();
114 }
115 
116 
117 void
118 MSDevice_Routing::buildVehicleDevices(SUMOVehicle& v, std::vector<MSDevice*>& into) {
119  bool needRerouting = v.getParameter().wasSet(VEHPARS_FORCE_REROUTE);
121  if (!needRerouting && oc.getFloat("device.rerouting.probability") == 0 && !oc.isSet("device.rerouting.explicit")) {
122  // no route computation is modelled
123  return;
124  }
125  needRerouting |= equippedByDefaultAssignmentOptions(OptionsCont::getOptions(), "rerouting", v);
126  if (needRerouting) {
127  // route computation is enabled
128  myWithTaz = oc.getBool("device.rerouting.with-taz");
129  const SUMOTime period = string2time(oc.getString("device.rerouting.period"));
130  const SUMOTime prePeriod = string2time(oc.getString("device.rerouting.pre-period"));
131  // initialise edge efforts if not done before
132  if (myEdgeEfforts.size() == 0) {
133  const std::vector<MSEdge*>& edges = MSNet::getInstance()->getEdgeControl().getEdges();
134  const bool useLoaded = oc.getBool("device.rerouting.init-with-loaded-weights");
135  const SUMOReal currentSecond = SIMTIME;
136  for (std::vector<MSEdge*>::const_iterator i = edges.begin(); i != edges.end(); ++i) {
137  while ((*i)->getNumericalID() >= (int)myEdgeEfforts.size()) {
138  myEdgeEfforts.push_back(0);
139  }
140  if (useLoaded) {
141  myEdgeEfforts[(*i)->getNumericalID()] = MSNet::getTravelTime(*i, 0, currentSecond);
142  } else {
143  myEdgeEfforts[(*i)->getNumericalID()] = (*i)->getCurrentTravelTime();
144  }
145  }
147  }
148  // make the weights be updated
149  if (myAdaptationInterval == -1) {
150  myAdaptationInterval = string2time(oc.getString("device.rerouting.adaptation-interval"));
151  if (myAdaptationInterval < 0) {
152  WRITE_ERROR("Negative value for device.rerouting.adaptation-interval!");
153  }
154  myAdaptationWeight = oc.getFloat("device.rerouting.adaptation-weight");
155  if (myAdaptationWeight < 0. || myAdaptationWeight > 1.) {
156  WRITE_ERROR("The value for device.rerouting.adaptation-weight must be between 0 and 1!");
157  }
158  if (myAdaptationWeight < 1. && myAdaptationInterval > 0) {
162  } else if (period > 0) {
163  WRITE_WARNING("Rerouting is useless if the edge weights do not get updated!");
164  }
165  }
166  if (myWithTaz) {
167  if (MSEdge::dictionary(v.getParameter().fromTaz + "-source") == 0) {
168  WRITE_ERROR("Source district '" + v.getParameter().fromTaz + "' not known when rerouting '" + v.getID() + "'!");
169  return;
170  }
171  if (MSEdge::dictionary(v.getParameter().toTaz + "-sink") == 0) {
172  WRITE_ERROR("Destination district '" + v.getParameter().toTaz + "' not known when rerouting '" + v.getID() + "'!");
173  return;
174  }
175  }
176  // build the device
177  into.push_back(new MSDevice_Routing(v, "routing_" + v.getID(), period, prePeriod));
178  }
179 }
180 
181 
182 // ---------------------------------------------------------------------------
183 // MSDevice_Routing-methods
184 // ---------------------------------------------------------------------------
185 MSDevice_Routing::MSDevice_Routing(SUMOVehicle& holder, const std::string& id,
186  SUMOTime period, SUMOTime preInsertionPeriod)
187  : MSDevice(holder, id), myPeriod(period), myPreInsertionPeriod(preInsertionPeriod), myLastRouting(-1), mySkipRouting(-1), myRerouteCommand(0) {
188  // we do always a pre insertion reroute to fill the best lanes of the vehicle with somehow meaningful values (especially for deaprtLane="best")
190  // if we don't update the edge weights, we might as well reroute now and hopefully use our threads better
191  const SUMOTime execTime = myEdgeWeightSettingCommand == 0 ? 0 : holder.getParameter().depart;
193  myRerouteCommand, execTime,
195 }
196 
197 
199  // make the rerouting command invalid if there is one
200  if (myRerouteCommand != 0 && MSNet::getInstance()->getInsertionEvents() != 0) {
202  }
203 }
204 
205 
206 bool
209  // clean up pre depart rerouting
210  if (myPreInsertionPeriod > 0) {
212  }
213  myRerouteCommand = 0;
214  // build repetition trigger if routing shall be done more often
215  if (myPeriod > 0) {
218  myRerouteCommand, myPeriod + MSNet::getInstance()->getCurrentTimeStep(),
220  }
221  }
222  return false;
223 }
224 
225 
226 SUMOTime
228  if (mySkipRouting == currentTime) {
229  return DELTA_T;
230  }
231  if (myWithTaz) {
232  const MSEdge* source = MSEdge::dictionary(myHolder.getParameter().fromTaz + "-source");
233  const MSEdge* dest = MSEdge::dictionary(myHolder.getParameter().toTaz + "-sink");
234  if (source && dest) {
235  const std::pair<const MSEdge*, const MSEdge*> key = std::make_pair(source, dest);
236  if (myCachedRoutes.find(key) == myCachedRoutes.end()) {
237  reroute(currentTime, true);
238  } else {
240  }
241  }
242  } else {
243  reroute(currentTime, true);
244  }
245  return myPreInsertionPeriod;
246 }
247 
248 
249 SUMOTime
251  reroute(currentTime);
252  return myPeriod;
253 }
254 
255 
256 SUMOReal
257 MSDevice_Routing::getEffort(const MSEdge* const e, const SUMOVehicle* const v, SUMOReal) {
258  const int id = e->getNumericalID();
259  if (id < (int)myEdgeEfforts.size()) {
260  return MAX2(myEdgeEfforts[id], e->getMinimumTravelTime(v));
261  }
262  return 0;
263 }
264 
265 
266 SUMOTime
268  if (MSNet::getInstance()->getVehicleControl().getDepartedVehicleNo() == 0) {
269  return myAdaptationInterval;
270  }
271  std::map<std::pair<const MSEdge*, const MSEdge*>, const MSRoute*>::iterator it = myCachedRoutes.begin();
272  for (; it != myCachedRoutes.end(); ++it) {
273  it->second->release();
274  }
275  myCachedRoutes.clear();
276  const SUMOReal newWeightFactor = (SUMOReal)(1. - myAdaptationWeight);
277  const std::vector<MSEdge*>& edges = MSNet::getInstance()->getEdgeControl().getEdges();
278  for (std::vector<MSEdge*>::const_iterator i = edges.begin(); i != edges.end(); ++i) {
279  const int id = (*i)->getNumericalID();
280  const SUMOReal currTT = (*i)->getCurrentTravelTime();
281  if (currTT != myEdgeEfforts[id]) {
282  myEdgeEfforts[id] = myEdgeEfforts[id] * myAdaptationWeight + currTT * newWeightFactor;
283  }
284  }
285  myLastAdaptation = currentTime + DELTA_T; // because we run at the end of the time step
286  return myAdaptationInterval;
287 }
288 
289 
290 void
291 MSDevice_Routing::reroute(const SUMOTime currentTime, const bool onInit) {
292  //check whether the weights did change since the last reroute
294  return;
295  }
296  myLastRouting = currentTime;
297 #ifdef HAVE_FOX
298  const bool needThread = (myRouter == 0 && myThreadPool.isFull());
299 #else
300  const bool needThread = true;
301 #endif
302  if (needThread && myRouter == 0) {
304  const std::string routingAlgorithm = oc.getString("routing-algorithm");
305  const bool mayHaveRestrictions = MSNet::getInstance()->hasRestrictions() || oc.getInt("remote-port") != 0;
306  if (routingAlgorithm == "dijkstra") {
307  if (mayHaveRestrictions) {
310  } else {
313  }
314  } else if (routingAlgorithm == "astar") {
315  if (mayHaveRestrictions) {
317  const AStar::LookupTable* lookup = 0;
318  if (oc.isSet("device.rerouting.shortest-path-file")) {
319  lookup = AStar::createLookupTable(oc.getString("device.rerouting.shortest-path-file"), (int)MSEdge::numericalDictSize());
320  }
321  myRouter = new AStar(MSEdge::numericalDictSize(), true, &MSDevice_Routing::getEffort, lookup);
322  } else {
324  const AStar::LookupTable* lookup = 0;
325  if (oc.isSet("device.rerouting.shortest-path-file")) {
326  lookup = AStar::createLookupTable(oc.getString("device.rerouting.shortest-path-file"), (int)MSEdge::numericalDictSize());
327  }
328  myRouter = new AStar(MSEdge::numericalDictSize(), true, &MSDevice_Routing::getEffort, lookup);
329  }
330  } else if (routingAlgorithm == "CH") {
332  if (mayHaveRestrictions) {
335  } else {
337  MSEdge::numericalDictSize(), true, &MSDevice_Routing::getEffort, myHolder.getVClass(), weightPeriod, false);
338  }
339  } else if (routingAlgorithm == "CHWrapper") {
340  const SUMOTime begin = string2time(oc.getString("begin"));
343  MSEdge::numericalDictSize(), true, &MSDevice_Routing::getEffort, begin, weightPeriod);
344  } else {
345  throw ProcessError("Unknown routing algorithm '" + routingAlgorithm + "'!");
346  }
347  }
348 #ifdef HAVE_FOX
349  if (needThread) {
350  const int numThreads = OptionsCont::getOptions().getInt("device.rerouting.threads");
351  if (myThreadPool.size() < numThreads) {
352  new WorkerThread(myThreadPool, myRouter);
353  }
354  if (myThreadPool.size() < numThreads) {
355  myRouter = 0;
356  }
357  }
358  if (myThreadPool.size() > 0) {
359  myThreadPool.add(new RoutingTask(myHolder, currentTime, onInit));
360  return;
361  }
362 #endif
363  myHolder.reroute(currentTime, *myRouter, onInit);
364 }
365 
366 
367 void
369 #ifdef HAVE_FOX
370  if (myThreadPool.size() > 0) {
371  // we cannot wait for the static destructor to do the cleanup
372  // because the output devices are gone by then
373  myThreadPool.clear();
374  // router deletion is done in thread destructor
375  myRouter = 0;
376  return;
377  }
378 #endif
379  delete myRouter;
380  myRouter = 0;
381 }
382 
383 
384 #ifdef HAVE_FOX
385 void
386 MSDevice_Routing::waitForAll() {
387  if (myThreadPool.size() > 0) {
388  myThreadPool.waitAll();
389  }
390 }
391 
392 
393 // ---------------------------------------------------------------------------
394 // MSDevice_Routing::RoutingTask-methods
395 // ---------------------------------------------------------------------------
396 void
397 MSDevice_Routing::RoutingTask::run(FXWorkerThread* context) {
398  myVehicle.reroute(myTime, static_cast<WorkerThread*>(context)->getRouter(), myOnInit);
399  if (myOnInit) {
400  const MSEdge* source = MSEdge::dictionary(myVehicle.getParameter().fromTaz + "-source");
401  const MSEdge* dest = MSEdge::dictionary(myVehicle.getParameter().toTaz + "-sink");
402  const std::pair<const MSEdge*, const MSEdge*> key = std::make_pair(source, dest);
403  lock();
405  MSDevice_Routing::myCachedRoutes[key] = &myVehicle.getRoute();
406  myVehicle.getRoute().addReference();
407  }
408  unlock();
409  }
410 }
411 #endif
412 
413 
414 /****************************************************************************/
415 
Computes the shortest path through a contracted network.
Definition: CHRouter.h:74
SUMOTime myPeriod
The period with which a vehicle shall be rerouted.
void doRegister(const std::string &name, Option *v)
Adds an option under the given name.
Definition: OptionsCont.cpp:84
const int VEHPARS_FORCE_REROUTE
SUMOTime mySkipRouting
The time for which routing may be skipped because we cannot be inserted.
static size_t numericalDictSize()
Returns the number of edges with a numerical id.
Definition: MSEdge.cpp:563
static SUMOTime adaptEdgeEfforts(SUMOTime currentTime)
Adapt edge efforts by the current edge states.
SUMOVehicle & myHolder
The vehicle that stores the device.
Definition: MSDevice.h:153
static SUMOTime myAdaptationInterval
At which time interval the edge weights get updated.
virtual void reroute(SUMOTime t, SUMOAbstractRouter< MSEdge, SUMOVehicle > &router, bool withTaz=false)=0
Performs a rerouting using the given router.
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
SUMOTime myLastRouting
The last time a routing took place.
MSDevice_Routing(SUMOVehicle &holder, const std::string &id, SUMOTime period, SUMOTime preInsertionPeriod)
Constructor.
Notification
Definition of a vehicle state.
Computes the shortest path through a network using the Dijkstra algorithm.
Definition: AStarRouter.h:71
static void buildVehicleDevices(SUMOVehicle &v, std::vector< MSDevice * > &into)
Build devices for the given vehicle, if needed.
SUMOTime myPreInsertionPeriod
The period with which a vehicle shall be rerouted before insertion.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:156
T MAX2(T a, T b)
Definition: StdDefs.h:74
static bool dictionary(const std::string &id, MSEdge *edge)
Inserts edge into the static dictionary Returns true if the key id isn&#39;t already in the dictionary...
Definition: MSEdge.cpp:523
SUMOTime wrappedRerouteCommandExecute(SUMOTime currentTime)
Performs rerouting after a period.
SUMOReal getFloat(const std::string &name) const
Returns the SUMOReal-value of the named option (only for Option_Float)
static Command * myEdgeWeightSettingCommand
The weights adaptation/overwriting command.
Base (microsim) event class.
Definition: Command.h:61
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:230
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:200
Computes the shortest path through a network using the Dijkstra algorithm.
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:67
#define SIMTIME
Definition: SUMOTime.h:96
std::string toTaz
The vehicle&#39;s destination zone (district)
void addSynonyme(const std::string &name1, const std::string &name2, bool isDeprecated=false)
Adds a synonyme for an options name (any order)
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
A road/street connecting two junctions.
Definition: MSEdge.h:75
virtual SUMOVehicleClass getVClass() const =0
Returns the vehicle&#39;s access class.
static void insertOptions(OptionsCont &oc)
Inserts MSDevice_Routing-options.
static bool myWithTaz
whether taz shall be used at initial rerouting
void reroute(const SUMOTime currentTime, const bool onInit=false)
initiate the rerouting, create router / thread pool on first use
#define max(a, b)
Definition: polyfonts.c:65
Representation of a vehicle.
Definition: SUMOVehicle.h:64
bool wasSet(int what) const
Returns whether the given parameter was set.
MSEventControl * getBeginOfTimestepEvents()
Returns the event control for events executed at the begin of a time step.
Definition: MSNet.h:354
static SUMOReal getTravelTime(const MSEdge *const e, const SUMOVehicle *const v, SUMOReal t)
Returns the travel time to pass an edge.
Definition: MSNet.cpp:138
static std::map< std::pair< const MSEdge *, const MSEdge * >, const MSRoute * > myCachedRoutes
The container of pre-calculated routes.
SUMOTime depart
The vehicle&#39;s departure time.
A wrapper for a Command function.
Definition: StaticCommand.h:49
SUMOTime string2time(const std::string &r)
Definition: SUMOTime.cpp:48
WrappingCommand< MSDevice_Routing > * myRerouteCommand
The (optional) command responsible for rerouting.
static void insertDefaultAssignmentOptions(const std::string &deviceName, const std::string &optionsTopic, OptionsCont &oc)
Adds common command options that allow to assign devices to vehicles.
Definition: MSDevice.cpp:84
std::string fromTaz
The vehicle&#39;s origin zone (district)
void addOptionSubTopic(const std::string &topic)
Adds an option subtopic.
virtual SUMOTime addEvent(Command *operation, SUMOTime execTimeStep, AdaptType type)
Adds an Event.
bool hasRestrictions() const
Returns whether the network has vehicle class restrictions.
Definition: MSNet.h:166
static SUMOReal getEffort(const MSEdge *const e, const SUMOVehicle *const v, SUMOReal t)
Returns the effort to pass an edge.
MSEventControl * getEndOfTimestepEvents()
Returns the event control for events executed at the end of a time step.
Definition: MSNet.h:364
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:205
Abstract in-vehicle device.
Definition: MSDevice.h:69
static bool equippedByDefaultAssignmentOptions(const OptionsCont &oc, const std::string &deviceName, SUMOVehicle &v)
Determines whether a vehicle should get a certain device.
Definition: MSDevice.cpp:98
A pool of worker threads which distributes the tasks and collects the results.
The vehicle has departed (was inserted into the network)
static std::vector< SUMOReal > myEdgeEfforts
The container of edge efforts.
An integer-option.
Definition: Option.h:309
int getNumericalID() const
Returns the numerical id of the edge.
Definition: MSEdge.h:244
void deschedule()
Marks this Command as being descheduled.
static SUMOAbstractRouter< MSEdge, SUMOVehicle > * myRouter
The router to use.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle&#39;s parameter (including departure definition)
A storage for options typed value containers)
Definition: OptionsCont.h:108
virtual bool replaceRoute(const MSRoute *route, bool onInit=false, int offset=0)=0
Replaces the current route by the given one.
int SUMOTime
Definition: SUMOTime.h:43
MSEventControl * getInsertionEvents()
Returns the event control for insertion events.
Definition: MSNet.h:374
bool notifyEnter(SUMOVehicle &veh, MSMoveReminder::Notification reason)
Computes a new route on vehicle insertion.
const std::vector< MSEdge * > & getEdges() const
Returns loaded edges.
~MSDevice_Routing()
Destructor.
Patch the time in a way that it is at least as high as the simulation begin time. ...
static void cleanup()
deletes the router instance
#define SUMOReal
Definition: config.h:218
SUMOReal getMinimumTravelTime(const SUMOVehicle *const veh) const
returns the minimum travel time for the given vehicle
Definition: MSEdge.h:389
A thread repeatingly calculating incoming tasks.
MSEdgeControl & getEdgeControl()
Returns the edge control.
Definition: MSNet.h:304
#define DELTA_T
Definition: SUMOTime.h:50
static SUMOReal myAdaptationWeight
Information which weight prior edge efforts have.
void addDescription(const std::string &name, const std::string &subtopic, const std::string &description)
Adds a description for an option.
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
static SUMOTime myLastAdaptation
Information when the last edge weight adaptation occured.
virtual const std::string & getID() const =0
Get the vehicle&#39;s ID.
SUMOTime preInsertionReroute(const SUMOTime currentTime)
Performs rerouting before insertion into the network.
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
Computes the shortest path through a contracted network.