SUMO - Simulation of Urban MObility
RORouteDef.cpp
Go to the documentation of this file.
1 /****************************************************************************/
9 // Base class for a vehicle's route definition
10 /****************************************************************************/
11 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
12 // Copyright (C) 2002-2017 DLR (http://www.dlr.de/) and contributors
13 /****************************************************************************/
14 //
15 // This file is part of SUMO.
16 // SUMO is free software: you can redistribute it and/or modify
17 // it under the terms of the GNU General Public License as published by
18 // the Free Software Foundation, either version 3 of the License, or
19 // (at your option) any later version.
20 //
21 /****************************************************************************/
22 
23 
24 // ===========================================================================
25 // included modules
26 // ===========================================================================
27 #ifdef _MSC_VER
28 #include <windows_config.h>
29 #else
30 #include <config.h>
31 #endif
32 
33 #include <string>
34 #include <iterator>
35 #include <algorithm>
37 #include <utils/common/ToString.h>
38 #include <utils/common/Named.h>
44 #include "ROEdge.h"
45 #include "RORoute.h"
48 #include "RORouteDef.h"
49 #include "ROVehicle.h"
50 
51 // ===========================================================================
52 // static members
53 // ===========================================================================
54 bool RORouteDef::myUsingJTRR(false);
55 
56 // ===========================================================================
57 // method definitions
58 // ===========================================================================
59 RORouteDef::RORouteDef(const std::string& id, const int lastUsed,
60  const bool tryRepair, const bool mayBeDisconnected) :
61  Named(StringUtils::convertUmlaute(id)),
62  myPrecomputed(0), myLastUsed(lastUsed), myTryRepair(tryRepair), myMayBeDisconnected(mayBeDisconnected) {
63 }
64 
65 
67  for (std::vector<RORoute*>::iterator i = myAlternatives.begin(); i != myAlternatives.end(); i++) {
68  if (myRouteRefs.count(*i) == 0) {
69  delete *i;
70  }
71  }
72 }
73 
74 
75 void
77  myAlternatives.push_back(alt);
78 }
79 
80 
81 void
83  std::copy(alt->myAlternatives.begin(), alt->myAlternatives.end(),
84  back_inserter(myAlternatives));
85  std::copy(alt->myAlternatives.begin(), alt->myAlternatives.end(),
86  std::inserter(myRouteRefs, myRouteRefs.end()));
87 }
88 
89 
90 RORoute*
92  SUMOTime begin, const ROVehicle& veh) const {
93  if (myPrecomputed == 0) {
94  preComputeCurrentRoute(router, begin, veh);
95  }
96  return myPrecomputed;
97 }
98 
99 
100 void
102  SUMOTime begin, const ROVehicle& veh) const {
103  myNewRoute = false;
104  const OptionsCont& oc = OptionsCont::getOptions();
105  assert(myAlternatives[0]->getEdgeVector().size() > 0);
106  MsgHandler* mh = (OptionsCont::getOptions().getBool("ignore-errors") ?
108  if (myAlternatives[0]->getFirst()->prohibits(&veh) && (!oc.getBool("repair.from")
109  // do not try to reassign starting edge for trip input
110  || myMayBeDisconnected || myAlternatives[0]->getEdgeVector().size() < 2)) {
111  mh->inform("Vehicle '" + veh.getID() + "' is not allowed to depart on edge '" +
112  myAlternatives[0]->getFirst()->getID() + "'.");
113  return;
114  } else if (myAlternatives[0]->getLast()->prohibits(&veh) && (!oc.getBool("repair.to")
115  // do not try to reassign destination edge for trip input
116  || myMayBeDisconnected || myAlternatives[0]->getEdgeVector().size() < 2)) {
117  // this check is not strictly necessary unless myTryRepair is set.
118  // However, the error message is more helpful than "no connection found"
119  mh->inform("Vehicle '" + veh.getID() + "' is not allowed to arrive on edge '" +
120  myAlternatives[0]->getLast()->getID() + "'.");
121  return;
122  }
123  if (myTryRepair) {
124  ConstROEdgeVector newEdges;
125  if (repairCurrentRoute(router, begin, veh, myAlternatives[0]->getEdgeVector(), newEdges)) {
126  if (myAlternatives[0]->getEdgeVector() != newEdges) {
127  if (!myMayBeDisconnected) {
128  WRITE_WARNING("Repaired route of vehicle '" + veh.getID() + "'.");
129  }
130  myNewRoute = true;
131  RGBColor* col = myAlternatives[0]->getColor() != 0 ? new RGBColor(*myAlternatives[0]->getColor()) : 0;
132  myPrecomputed = new RORoute(myID, 0, myAlternatives[0]->getProbability(), newEdges, col, myAlternatives[0]->getStops());
133  } else {
135  }
136  }
137  return;
138  }
140  || OptionsCont::getOptions().getBool("remove-loops")) {
142  } else {
143  // build a new route to test whether it is better
144  ConstROEdgeVector oldEdges;
145  oldEdges.push_back(myAlternatives[0]->getFirst());
146  oldEdges.push_back(myAlternatives[0]->getLast());
147  ConstROEdgeVector edges;
148  repairCurrentRoute(router, begin, veh, oldEdges, edges);
149  // check whether the same route was already used
150  int cheapest = -1;
151  for (int i = 0; i < (int)myAlternatives.size(); i++) {
152  if (edges == myAlternatives[i]->getEdgeVector()) {
153  cheapest = i;
154  break;
155  }
156  }
157  if (cheapest >= 0) {
158  myPrecomputed = myAlternatives[cheapest];
159  } else {
160  RGBColor* col = myAlternatives[0]->getColor() != 0 ? new RGBColor(*myAlternatives[0]->getColor()) : 0;
161  myPrecomputed = new RORoute(myID, 0, 1, edges, col, myAlternatives[0]->getStops());
162  myNewRoute = true;
163  }
164  }
165 }
166 
167 
168 bool
170  SUMOTime begin, const ROVehicle& veh,
171  ConstROEdgeVector oldEdges, ConstROEdgeVector& newEdges) const {
172  MsgHandler* mh = (OptionsCont::getOptions().getBool("ignore-errors") ?
174  ConstROEdgeVector mandatory;
175  const int initialSize = (int)oldEdges.size();
176  if (initialSize == 1) {
177  if (myUsingJTRR) {
179  router.compute(oldEdges.front(), 0, &veh, begin, newEdges);
180  } else {
181  newEdges = oldEdges;
182  }
183  } else {
184  // prepare mandatory edges
185  if (oldEdges.front()->prohibits(&veh)) {
186  // option repair.from is in effect
187  const std::string& frontID = oldEdges.front()->getID();
188  for (ConstROEdgeVector::iterator i = oldEdges.begin(); i != oldEdges.end();) {
189  if ((*i)->prohibits(&veh)) {
190  i = oldEdges.erase(i);
191  } else {
192  WRITE_MESSAGE("Changing invalid starting edge '" + frontID
193  + "' to '" + (*i)->getID() + "' for vehicle '" + veh.getID() + "'.");
194  break;
195  }
196  }
197  }
198  if (oldEdges.size() == 0) {
199  mh->inform("Could not find new starting edge for vehicle '" + veh.getID() + "'.");
200  return false;
201  }
202  mandatory.push_back(oldEdges.front());
203  ConstROEdgeVector stops = veh.getStopEdges();
204  for (ConstROEdgeVector::const_iterator i = stops.begin(); i != stops.end(); ++i) {
205  if ((*i)->isInternal()) {
206  // the edges before and after the internal edge are mandatory
207  const ROEdge* before = (*i)->getNormalBefore();
208  const ROEdge* after = (*i)->getNormalAfter();
209  if (after != mandatory.back()) {
210  mandatory.push_back(before);
211  mandatory.push_back(after);
212  }
213  } else {
214  if (*i != mandatory.back()) {
215  mandatory.push_back(*i);
216  }
217  }
218  }
219  if (oldEdges.back()->prohibits(&veh)) {
220  // option repair.to is in effect
221  const std::string& backID = oldEdges.back()->getID();
222  // oldEdges cannot get empty here, otherwise we would have left the stage when checking "from"
223  while (oldEdges.back()->prohibits(&veh)) {
224  oldEdges.pop_back();
225  }
226  WRITE_MESSAGE("Changing invalid destination edge '" + backID
227  + "' to edge '" + oldEdges.back()->getID() + "' for vehicle '" + veh.getID() + "'.");
228  }
229  if (mandatory.size() < 2 || oldEdges.back() != mandatory.back()) {
230  mandatory.push_back(oldEdges.back());
231  }
232  assert(mandatory.size() >= 2);
233  // removed prohibited
234  for (ConstROEdgeVector::iterator i = oldEdges.begin(); i != oldEdges.end();) {
235  if ((*i)->prohibits(&veh)) {
236  // no need to check the mandatories here, this was done before
237  i = oldEdges.erase(i);
238  } else {
239  ++i;
240  }
241  }
242  // reconnect remaining edges
243  if (mandatory.size() > oldEdges.size() && initialSize > 2) {
244  WRITE_MESSAGE("There are stop edges which were not part of the original route for vehicle '" + veh.getID() + "'.");
245  }
246  const ConstROEdgeVector& targets = mandatory.size() > oldEdges.size() ? mandatory : oldEdges;
247  newEdges.push_back(*(targets.begin()));
248  ConstROEdgeVector::iterator nextMandatory = mandatory.begin() + 1;
249  int lastMandatory = 0;
250  for (ConstROEdgeVector::const_iterator i = targets.begin() + 1;
251  i != targets.end() && nextMandatory != mandatory.end(); ++i) {
252  if ((*(i - 1))->isConnectedTo(*i, &veh)) {
253  newEdges.push_back(*i);
254  } else {
255  if (initialSize > 2) {
256  // only inform if the input is (probably) not a trip
257  WRITE_MESSAGE("Edge '" + (*(i - 1))->getID() + "' not connected to edge '" + (*i)->getID() + "' for vehicle '" + veh.getID() + "'.");
258  }
259  const ROEdge* const last = newEdges.back();
260  newEdges.pop_back();
261  if (!router.compute(last, *i, &veh, begin, newEdges)) {
262  // backtrack: try to route from last mandatory edge to next mandatory edge
263  // XXX add option for backtracking in smaller increments
264  // (i.e. previous edge to edge after *i)
265  // we would then need to decide whether we have found a good
266  // tradeoff between faithfulness to the input data and detour-length
267  ConstROEdgeVector edges;
268  if (lastMandatory >= (int)newEdges.size() || last == newEdges[lastMandatory] || !router.compute(newEdges[lastMandatory], *nextMandatory, &veh, begin, edges)) {
269  mh->inform("Mandatory edge '" + (*i)->getID() + "' not reachable by vehicle '" + veh.getID() + "'.");
270  return false;
271  }
272  while (*i != *nextMandatory) {
273  ++i;
274  }
275  newEdges.erase(newEdges.begin() + lastMandatory + 1, newEdges.end());
276  std::copy(edges.begin() + 1, edges.end(), back_inserter(newEdges));
277  }
278  }
279  if (*i == *nextMandatory) {
280  nextMandatory++;
281  lastMandatory = (int)newEdges.size() - 1;
282  }
283  }
284  }
285  return true;
286 }
287 
288 
289 void
291  const ROVehicle* const veh, RORoute* current, SUMOTime begin) {
292  if (myTryRepair) {
293  if (myNewRoute) {
294  delete myAlternatives[0];
295  myAlternatives[0] = current;
296  }
297  const double costs = router.recomputeCosts(current->getEdgeVector(), veh, begin);
298  if (costs < 0) {
299  throw ProcessError("Route '" + getID() + "' (vehicle '" + veh->getID() + "') is not valid.");
300  }
301  current->setCosts(costs);
302  return;
303  }
304  // add the route when it's new
305  if (myNewRoute) {
306  myAlternatives.push_back(current);
307  }
308  // recompute the costs and (when a new route was added) scale the probabilities
309  const double scale = double(myAlternatives.size() - 1) / double(myAlternatives.size());
310  for (std::vector<RORoute*>::iterator i = myAlternatives.begin(); i != myAlternatives.end(); i++) {
311  RORoute* alt = *i;
312  // recompute the costs for all routes
313  const double newCosts = router.recomputeCosts(alt->getEdgeVector(), veh, begin);
314  if (newCosts < 0.) {
315  throw ProcessError("Route '" + current->getID() + "' (vehicle '" + veh->getID() + "') is not valid.");
316  }
317  assert(myAlternatives.size() != 0);
318  if (myNewRoute) {
319  if (*i == current) {
320  // set initial probability and costs
321  alt->setProbability((double)(1.0 / (double) myAlternatives.size()));
322  alt->setCosts(newCosts);
323  } else {
324  // rescale probs for all others
325  alt->setProbability(alt->getProbability() * scale);
326  }
327  }
329  }
330  assert(myAlternatives.size() != 0);
333  // remove with probability of 0 (not mentioned in Gawron)
334  for (std::vector<RORoute*>::iterator i = myAlternatives.begin(); i != myAlternatives.end();) {
335  if ((*i)->getProbability() == 0) {
336  delete *i;
337  i = myAlternatives.erase(i);
338  } else {
339  i++;
340  }
341  }
342  }
343  if ((int)myAlternatives.size() > RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().getMaxRouteNumber()) {
344  // only keep the routes with highest probability
345  sort(myAlternatives.begin(), myAlternatives.end(), ComparatorProbability());
346  for (std::vector<RORoute*>::iterator i = myAlternatives.begin() + RouteCostCalculator<RORoute, ROEdge, ROVehicle>::getCalculator().getMaxRouteNumber(); i != myAlternatives.end(); i++) {
347  delete *i;
348  }
350  // rescale probabilities
351  double newSum = 0;
352  for (std::vector<RORoute*>::iterator i = myAlternatives.begin(); i != myAlternatives.end(); i++) {
353  newSum += (*i)->getProbability();
354  }
355  assert(newSum > 0);
356  // @note newSum may be larger than 1 for numerical reasons
357  for (std::vector<RORoute*>::iterator i = myAlternatives.begin(); i != myAlternatives.end(); i++) {
358  (*i)->setProbability((*i)->getProbability() / newSum);
359  }
360  }
361 
362  // find the route to use
363  double chosen = RandHelper::rand();
364  int pos = 0;
365  for (std::vector<RORoute*>::iterator i = myAlternatives.begin(); i != myAlternatives.end() - 1; i++, pos++) {
366  chosen -= (*i)->getProbability();
367  if (chosen <= 0) {
368  myLastUsed = pos;
369  return;
370  }
371  }
372  myLastUsed = pos;
373 }
374 
375 
376 const ROEdge*
378  return myAlternatives[0]->getLast();
379 }
380 
381 
384  bool asAlternatives, bool withExitTimes) const {
385  if (asAlternatives) {
387  for (int i = 0; i != (int)myAlternatives.size(); i++) {
388  myAlternatives[i]->writeXMLDefinition(dev, veh, true, withExitTimes);
389  }
390  dev.closeTag();
391  return dev;
392  } else {
393  return myAlternatives[myLastUsed]->writeXMLDefinition(dev, veh, false, withExitTimes);
394  }
395 }
396 
397 
398 RORouteDef*
399 RORouteDef::copyOrigDest(const std::string& id) const {
400  RORouteDef* result = new RORouteDef(id, 0, true, true);
401  RORoute* route = myAlternatives[0];
402  RGBColor* col = route->getColor() != 0 ? new RGBColor(*route->getColor()) : 0;
403  ConstROEdgeVector edges;
404  edges.push_back(route->getFirst());
405  edges.push_back(route->getLast());
406  result->addLoadedAlternative(new RORoute(id, 0, 1, edges, col, route->getStops()));
407  return result;
408 }
409 
410 
411 RORouteDef*
412 RORouteDef::copy(const std::string& id, const SUMOTime stopOffset) const {
413  RORouteDef* result = new RORouteDef(id, 0, myTryRepair, myMayBeDisconnected);
414  for (std::vector<RORoute*>::const_iterator i = myAlternatives.begin(); i != myAlternatives.end(); i++) {
415  RORoute* route = *i;
416  RGBColor* col = route->getColor() != 0 ? new RGBColor(*route->getColor()) : 0;
417  RORoute* newRoute = new RORoute(id, 0, 1, route->getEdgeVector(), col, route->getStops());
418  newRoute->addStopOffset(stopOffset);
419  result->addLoadedAlternative(newRoute);
420  }
421  return result;
422 }
423 
424 
425 double
427  double sum = 0.;
428  for (std::vector<RORoute*>::const_iterator i = myAlternatives.begin(); i != myAlternatives.end(); i++) {
429  sum += (*i)->getProbability();
430  }
431  return sum;
432 }
433 
434 
435 /****************************************************************************/
SUMOTime getDepartureTime() const
Returns the time the vehicle starts at, 0 for triggered vehicles.
Definition: ROVehicle.h:111
int myLastUsed
Index of the route used within the last step.
Definition: RORouteDef.h:159
static MsgHandler * getWarningInstance()
Returns the instance to add warnings to.
Definition: MsgHandler.cpp:67
void setProbability(double prob)
Sets the probability of the route.
Definition: RORoute.cpp:79
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:261
bool myNewRoute
Information whether a new route was generated.
Definition: RORouteDef.h:168
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
Definition: MsgHandler.cpp:76
RORouteDef * copyOrigDest(const std::string &id) const
Returns a origin-destination copy of the route definition.
Definition: RORouteDef.cpp:399
const bool myTryRepair
Definition: RORouteDef.h:170
bool repairCurrentRoute(SUMOAbstractRouter< ROEdge, ROVehicle > &router, SUMOTime begin, const ROVehicle &veh, ConstROEdgeVector oldEdges, ConstROEdgeVector &newEdges) const
Builds the complete route (or chooses her from the list of alternatives, when existing) ...
Definition: RORouteDef.cpp:169
double getOverallProb() const
Returns the sum of the probablities of the contained routes.
Definition: RORouteDef.cpp:426
distribution of a route
Some static methods for string processing.
Definition: StringUtils.h:45
void addAlternative(SUMOAbstractRouter< ROEdge, ROVehicle > &router, const ROVehicle *const, RORoute *current, SUMOTime begin)
Adds an alternative to the list of routes.
Definition: RORouteDef.cpp:290
RORoute * buildCurrentRoute(SUMOAbstractRouter< ROEdge, ROVehicle > &router, SUMOTime begin, const ROVehicle &veh) const
Triggers building of the complete route (via preComputeCurrentRoute) or returns precomputed route...
Definition: RORouteDef.cpp:91
void addAlternativeDef(const RORouteDef *alternative)
Adds an alternative loaded from the file.
Definition: RORouteDef.cpp:82
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
static double rand(std::mt19937 *rng=0)
Returns a random real number in [0, 1)
Definition: RandHelper.h:65
const ConstROEdgeVector & getEdgeVector() const
Returns the list of edges this route consists of.
Definition: RORoute.h:162
virtual bool compute(const E *from, const E *to, const V *const vehicle, SUMOTime msTime, std::vector< const E * > &into)=0
Builds the route between the given edges using the minimum effort at the given time The definition of...
void preComputeCurrentRoute(SUMOAbstractRouter< ROEdge, ROVehicle > &router, SUMOTime begin, const ROVehicle &veh) const
Builds the complete route (or chooses her from the list of alternatives, when existing) ...
Definition: RORouteDef.cpp:101
void addStopOffset(const SUMOTime offset)
Adapts the until time of all stops by the given offset.
Definition: RORoute.h:197
std::vector< const ROEdge * > ConstROEdgeVector
Definition: ROEdge.h:63
static bool myUsingJTRR
Definition: RORouteDef.h:173
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:200
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:65
RORoute * myPrecomputed
precomputed route for out-of-order computation
Definition: RORouteDef.h:156
const std::string & getID() const
Returns the id.
Definition: Named.h:66
const bool myMayBeDisconnected
Definition: RORouteDef.h:171
A vehicle as used by router.
Definition: ROVehicle.h:60
const ROEdge * getLast() const
Returns the last edge in the route.
Definition: RORoute.h:110
std::set< RORoute * > myRouteRefs
Routes which are deleted someplace else.
Definition: RORouteDef.h:165
OutputDevice & writeXMLDefinition(OutputDevice &dev, const ROVehicle *const veh, bool asAlternatives, bool withExitTimes) const
Saves the built route / route alternatives.
Definition: RORouteDef.cpp:383
const RGBColor * getColor() const
Returns this route&#39;s color.
Definition: RORoute.h:170
RORouteDef(const std::string &id, const int lastUsed, const bool tryRepair, const bool mayBeDisconnected)
Constructor.
Definition: RORouteDef.cpp:59
Abstract base class providing static factory method.
const ROEdge * getDestination() const
Definition: RORouteDef.cpp:377
const ROEdge * getFirst() const
Returns the first edge in the route.
Definition: RORoute.h:101
A basic edge for routing applications.
Definition: ROEdge.h:78
Base class for objects which have an id.
Definition: Named.h:46
virtual ~RORouteDef()
Destructor.
Definition: RORouteDef.cpp:66
virtual double recomputeCosts(const std::vector< const E * > &edges, const V *const v, SUMOTime msTime) const =0
std::string myID
The name of the object.
Definition: Named.h:136
const ConstROEdgeVector & getStopEdges() const
Definition: ROVehicle.h:116
RORouteDef * copy(const std::string &id, const SUMOTime stopOffset) const
Returns a deep copy of the route definition.
Definition: RORouteDef.cpp:412
const std::string & getID() const
Returns the id of the vehicle.
Definition: RORoutable.h:92
void setCosts(double costs)
Sets the costs of the route.
Definition: RORoute.cpp:73
void inform(std::string msg, bool addType=true)
adds a new error to the list
Definition: MsgHandler.cpp:85
A storage for options typed value containers)
Definition: OptionsCont.h:99
Base class for a vehicle&#39;s route definition.
Definition: RORouteDef.h:63
const ROEdge * getNormalAfter() const
if this edge is an internal edge, return its first normal successor, otherwise the edge itself ...
Definition: ROEdge.cpp:264
void addLoadedAlternative(RORoute *alternative)
Adds a single alternative loaded from the file An alternative may also be generated during DUA...
Definition: RORouteDef.cpp:76
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:71
bool closeTag()
Closes the most recently opened tag.
const ROEdge * getNormalBefore() const
if this edge is an internal edge, return its first normal predecessor, otherwise the edge itself ...
Definition: ROEdge.cpp:253
long long int SUMOTime
Definition: TraCIDefs.h:52
static RouteCostCalculator< R, E, V > & getCalculator()
double getProbability() const
Returns the probability the driver will take this route with.
Definition: RORoute.h:130
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:201
std::vector< RORoute * > myAlternatives
The alternatives.
Definition: RORouteDef.h:162
const std::vector< SUMOVehicleParameter::Stop > & getStops() const
Returns the list of stops this route contains.
Definition: RORoute.h:191
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
A complete router&#39;s route.
Definition: RORoute.h:62