SUMO - Simulation of Urban MObility
MELoop.cpp
Go to the documentation of this file.
1 /****************************************************************************/
7 // The main mesocopic simulation loop
8 /****************************************************************************/
9 // SUMO, Simulation of Urban MObility; see http://sumo.dlr.de/
10 // Copyright (C) 2001-2017 DLR (http://www.dlr.de/) and contributors
11 /****************************************************************************/
12 //
13 // This file is part of SUMO.
14 // SUMO is free software: you can redistribute it and/or modify
15 // it under the terms of the GNU General Public License as published by
16 // the Free Software Foundation, either version 3 of the License, or
17 // (at your option) any later version.
18 //
19 /****************************************************************************/
20 
21 
22 // ===========================================================================
23 // included modules
24 // ===========================================================================
25 #ifdef _MSC_VER
26 #include <windows_config.h>
27 #else
28 #include <config.h>
29 #endif
30 
31 #include <queue>
32 #include <vector>
33 #include <map>
34 #include <cmath>
35 
36 #include <microsim/MSNet.h>
37 #include <microsim/MSEdge.h>
38 #include <microsim/MSGlobals.h>
39 #include <microsim/MSLane.h>
40 #include <microsim/MSVehicle.h>
43 #include <utils/common/ToString.h>
45 #include <utils/common/SUMOTime.h>
47 #include "MELoop.h"
48 #include "MESegment.h"
49 #include "MEVehicle.h"
50 
51 
52 // ===========================================================================
53 // method definitions
54 // ===========================================================================
55 MELoop::MELoop(const SUMOTime recheckInterval) : myFullRecheckInterval(recheckInterval), myLinkRecheckInterval(TIME2STEPS(1)) {
56 }
57 
59  for (std::vector<MESegment*>::const_iterator j = myEdges2FirstSegments.begin(); j != myEdges2FirstSegments.end(); ++j) {
60  for (MESegment* s = *j; s != 0;) {
61  MESegment* n = s->getNextSegment();
62  delete s;
63  s = n;
64  }
65  }
66 }
67 
68 
69 void
71  while (!myLeaderCars.empty()) {
72  const SUMOTime time = myLeaderCars.begin()->first;
73  assert(time > tMax - DELTA_T);
74  if (time > tMax) {
75  return;
76  }
77  std::vector<MEVehicle*> vehs = myLeaderCars[time];
78  myLeaderCars.erase(time);
79  for (std::vector<MEVehicle*>::const_iterator i = vehs.begin(); i != vehs.end(); ++i) {
80  checkCar(*i);
81  assert(myLeaderCars.empty() || myLeaderCars.begin()->first >= time);
82  }
83  }
84 }
85 
86 
87 bool
88 MELoop::changeSegment(MEVehicle* veh, SUMOTime leaveTime, MESegment* const toSegment, const bool ignoreLink) {
89  MESegment* const onSegment = veh->getSegment();
90  if (MESegment::isInvalid(toSegment)) {
91  if (onSegment != 0) {
92  onSegment->send(veh, toSegment, leaveTime);
93  } else {
94  WRITE_WARNING("Vehicle '" + veh->getID() + "' teleports beyond arrival edge '" + veh->getEdge()->getID() + "', time " + time2string(leaveTime) + ".");
95  }
96  veh->setSegment(toSegment); // signal arrival
98  return true;
99  }
100  if (toSegment->hasSpaceFor(veh, leaveTime) && (ignoreLink || veh->mayProceed())) {
101  if (onSegment != 0) {
102  onSegment->send(veh, toSegment, leaveTime);
103  toSegment->receive(veh, leaveTime, false, ignoreLink);
104  } else {
105  WRITE_WARNING("Vehicle '" + veh->getID() + "' ends teleporting on edge '" + toSegment->getEdge().getID()
106  + "':" + toString(toSegment->getIndex()) + ", time " + time2string(leaveTime) + ".");
107  // this is not quite correct but suffices for interrogation by
108  // subsequent methods (veh->getSpeed() needs segment != 0)
110  toSegment->receive(veh, leaveTime, false, true);
111  }
112  return true;
113  }
114  return false;
115 }
116 
117 
118 void
120  const SUMOTime leaveTime = veh->getEventTime();
121  MESegment* const onSegment = veh->getSegment();
122  MESegment* const toSegment = nextSegment(onSegment, veh);
123  const bool teleporting = (onSegment == 0); // is the vehicle currently teleporting?
124  if (changeSegment(veh, leaveTime, toSegment, teleporting)) {
125  return;
126  }
128  teleportVehicle(veh, toSegment);
129  return;
130  }
131  if (veh->getBlockTime() == SUMOTime_MAX) {
132  veh->setBlockTime(leaveTime);
133  }
134  if (leaveTime < toSegment->getEntryBlockTime()) {
135  // receiving segment has recently received another vehicle
136  veh->setEventTime(toSegment->getEntryBlockTime());
137  } else if (toSegment->hasSpaceFor(veh, leaveTime) && !veh->mayProceed()) {
138  // either the junction is blocked or the traffic light is red
139  veh->setEventTime(leaveTime + MAX2(SUMOTime(1), myLinkRecheckInterval));
140  } else {
141  SUMOTime newEventTime = MAX3(toSegment->getEventTime() + 1, leaveTime + 1, leaveTime + myFullRecheckInterval);
142  if (MSGlobals::gTimeToGridlock > 0) {
143  // if teleporting is enabled, make sure we look at the vehicle when the the gridlock-time is up
144  newEventTime = MIN2(newEventTime, veh->getBlockTime() + MSGlobals::gTimeToGridlock + 1);
145  }
146  veh->setEventTime(newEventTime);
147  }
148  addLeaderCar(veh, onSegment->getLink(veh));
149 }
150 
151 
152 void
153 MELoop::teleportVehicle(MEVehicle* veh, MESegment* const toSegment) {
154  const SUMOTime leaveTime = veh->getEventTime();
155  MESegment* const onSegment = veh->getSegment();
156  const bool teleporting = (onSegment == 0); // is the vehicle already teleporting?
157  // try to find a place on the current edge
158  MESegment* teleSegment = toSegment->getNextSegment();
159  while (teleSegment != 0 && !teleSegment->hasSpaceFor(veh, leaveTime)) {
160  // @caution the time to get to the next segment here is ignored XXX
161  teleSegment = teleSegment->getNextSegment();
162  }
163  if (teleSegment != 0) {
164  if (!teleporting) {
165  // we managed to teleport in a single jump
166  WRITE_WARNING("Teleporting vehicle '" + veh->getID() + "'; waited too long, from edge '" + onSegment->getEdge().getID()
167  + "':" + toString(onSegment->getIndex())
168  + " to edge '" + teleSegment->getEdge().getID()
169  + "':" + toString(teleSegment->getIndex())
170  + ", time " + time2string(leaveTime) + ".");
172  }
173  changeSegment(veh, leaveTime, teleSegment, true);
174  teleSegment->setEntryBlockTime(leaveTime); // teleports should not block normal flow
175  } else {
176  // teleport across the current edge and try insertion later
177  if (!teleporting) {
178  // announce start of multi-step teleport, arrival will be announced in changeSegment()
179  WRITE_WARNING("Teleporting vehicle '" + veh->getID() + "'; waited too long, from edge '" + onSegment->getEdge().getID()
180  + "':" + toString(onSegment->getIndex()) + ", time " + time2string(leaveTime) + ".");
182  // remove from current segment
183  onSegment->send(veh, 0, leaveTime);
184  // mark veh as teleporting
185  veh->setSegment(0, 0);
186  }
187  // @caution microsim uses current travel time teleport duration
188  const SUMOTime teleArrival = leaveTime + TIME2STEPS(veh->getEdge()->getLength() / veh->getEdge()->getSpeedLimit());
189  const bool atDest = veh->moveRoutePointer();
190  if (atDest) {
191  // teleporting to end of route
192  changeSegment(veh, teleArrival, 0, true);
193  } else {
194  veh->setEventTime(teleArrival);
195  addLeaderCar(veh, 0);
196  // teleporting vehicles must react to rerouters
197  getSegmentForEdge(*veh->getEdge())->addReminders(veh);
199  }
200  }
201 }
202 
203 
204 void
206  myLeaderCars[veh->getEventTime()].push_back(veh);
207  setApproaching(veh, link);
208 }
209 
210 
211 void
213  if (link != 0) {
214  link->setApproaching(veh, veh->getEventTime() + (link->getState() == LINKSTATE_ALLWAY_STOP ?
215  (SUMOTime)RandHelper::rand((int)2) : 0), // tie braker
216  veh->getSpeed(), veh->getSpeed(), true,
217  veh->getEventTime(), veh->getSpeed(), veh->getWaitingTime(),
218  // @note: dist is not used by meso (getZipperSpeed is never called)
219  veh->getSegment()->getLength());
220  }
221 }
222 
223 
224 void
226  std::vector<MEVehicle*>& cands = myLeaderCars[v->getEventTime()];
227  cands.erase(find(cands.begin(), cands.end(), v));
228 }
229 
230 
231 MESegment*
233  if (s != 0) { // vehicle is not teleporting
234  MESegment* next = s->getNextSegment();
235  if (next != 0) {
236  // ok, the street continues
237  return next;
238  }
239  }
240  // we have to check the next edge in the vehicle's route
241  const MSEdge* nextEdge = v->succEdge(1);
242  if (nextEdge == 0) {
243  // end of route
244  return 0;
245  }
246  return myEdges2FirstSegments[nextEdge->getNumericalID()];
247 }
248 
249 
250 int
251 MELoop::numSegmentsFor(const double length, const double sLength) {
252  int no = (int)floor(length / sLength + 0.5);
253  if (no == 0) { // assure there is at least one segment
254  return 1;
255  } else {
256  return no;
257  }
258 }
259 
260 
261 void
263  const double length = e.getLength();
264  int no = numSegmentsFor(length, oc.getFloat("meso-edgelength"));
265  const double slength = length / (double)no;
266  MESegment* newSegment = 0;
267  MESegment* nextSegment = 0;
268  bool multiQueue = oc.getBool("meso-multi-queue");
269  bool junctionControl = oc.getBool("meso-junction-control");
270  for (int s = no - 1; s >= 0; s--) {
271  std::string id = e.getID() + ":" + toString(s);
272  newSegment =
273  new MESegment(id, e, nextSegment, slength,
274  e.getLanes()[0]->getSpeedLimit(), s,
275  string2time(oc.getString("meso-tauff")), string2time(oc.getString("meso-taufj")),
276  string2time(oc.getString("meso-taujf")), string2time(oc.getString("meso-taujj")),
277  oc.getFloat("meso-jam-threshold"), multiQueue, junctionControl);
278  multiQueue = false;
279  junctionControl = false;
280  nextSegment = newSegment;
281  }
282  while (e.getNumericalID() >= static_cast<int>(myEdges2FirstSegments.size())) {
283  myEdges2FirstSegments.push_back(0);
284  }
285  myEdges2FirstSegments[e.getNumericalID()] = newSegment;
286 }
287 
288 
289 MESegment*
290 MELoop::getSegmentForEdge(const MSEdge& e, double pos) {
292  if (pos > 0) {
293  double cpos = 0;
294  while (s->getNextSegment() != 0 && cpos + s->getLength() < pos) {
295  cpos += s->getLength();
296  s = s->getNextSegment();
297  }
298  }
299  return s;
300 }
301 
302 
303 /****************************************************************************/
double getLength() const
return the length of the edge
Definition: MSEdge.h:570
bool changeSegment(MEVehicle *veh, SUMOTime leaveTime, MESegment *const toSegment, const bool ignoreLink=false)
change to the next segment this handles combinations of the following cases: (ending / continuing rou...
Definition: MELoop.cpp:88
MELoop(const SUMOTime recheckInterval)
SUMO constructor.
Definition: MELoop.cpp:55
virtual void setSegment(MESegment *s, int idx=0)
Sets the current segment the vehicle is at together with its que.
Definition: MEVehicle.h:221
MESegment * nextSegment(MESegment *s, MEVehicle *v)
Retrieve next segment.
Definition: MELoop.cpp:232
SUMOTime getBlockTime() const
Returns the time at which the vehicle was blocked.
Definition: MEVehicle.h:271
A vehicle from the mesoscopic point of view.
Definition: MEVehicle.h:52
MESegment * getSegmentForEdge(const MSEdge &e, double pos=0)
Get the segment for a given edge at a given position.
Definition: MELoop.cpp:290
const std::vector< MSLane * > & getLanes() const
Returns this edge&#39;s lanes.
Definition: MSEdge.h:168
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
The vehicle arrived at a junction.
~MELoop()
Definition: MELoop.cpp:58
double getSpeedLimit() const
Returns the speed limit of the edge The speed limit of the first lane is retured; should probably be...
Definition: MSEdge.cpp:847
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
SUMOTime getWaitingTime() const
Returns the duration for which the vehicle was blocked.
Definition: MEVehicle.h:277
static double rand(std::mt19937 *rng=0)
Returns a random real number in [0, 1)
Definition: RandHelper.h:65
const SUMOTime myFullRecheckInterval
the interval at which to recheck at full segments (<=0 means asap)
Definition: MELoop.h:153
std::vector< MESegment * > myEdges2FirstSegments
mapping from internal edge ids to their initial segments
Definition: MELoop.h:150
void buildSegmentsFor(const MSEdge &e, const OptionsCont &oc)
Build the segments for a given edge.
Definition: MELoop.cpp:262
std::string time2string(SUMOTime t)
Definition: SUMOTime.cpp:60
void teleportVehicle(MEVehicle *veh, MESegment *const toSegment)
teleports a vehicle or continues a teleport
Definition: MELoop.cpp:153
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:169
T MAX2(T a, T b)
Definition: StdDefs.h:74
SUMOTime getEventTime() const
Returns the (planned) time at which the vehicle leaves his current cell.
Definition: MEVehicle.h:212
SUMOTime DELTA_T
Definition: SUMOTime.cpp:40
SUMOTime getEntryBlockTime() const
return the next time at which a vehicle my enter this segment
Definition: MESegment.h:365
double getSpeed() const
Returns the vehicle&#39;s estimated speed assuming no delays.
Definition: MEVehicle.cpp:110
#define TIME2STEPS(x)
Definition: SUMOTime.h:66
This is an uncontrolled, all-way stop link.
const MSEdge & getEdge() const
Returns the edge this segment belongs to.
Definition: MESegment.h:271
T MAX3(T a, T b, T c)
Definition: StdDefs.h:88
void setBlockTime(const SUMOTime t)
Sets the time at which the vehicle was blocked.
Definition: MEVehicle.h:262
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:200
void setEntryBlockTime(SUMOTime entryBlockTime)
set the next time at which a vehicle my enter this segment
Definition: MESegment.h:370
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
void removeLeaderCar(MEVehicle *v)
Removes the given car from the leading vehicles.
Definition: MELoop.cpp:225
MSLink * getLink(const MEVehicle *veh, bool tlsPenalty=false) const
Returns the link the given car will use when passing the next junction.
Definition: MESegment.cpp:395
const std::string & getID() const
Returns the id.
Definition: Named.h:66
A road/street connecting two junctions.
Definition: MSEdge.h:81
bool isStopped() const
Returns whether the vehicle is at a stop.
Definition: MEVehicle.cpp:234
void receive(MEVehicle *veh, SUMOTime time, bool isDepart=false, bool afterTeleport=false)
Adds the vehicle to the segment, adapting its parameters.
Definition: MESegment.cpp:487
MESegment * getNextSegment() const
Returns the following segment on the same edge (0 if it is the last).
Definition: MESegment.h:157
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:56
#define SUMOTime_MAX
Definition: TraCIDefs.h:53
static bool isInvalid(const MESegment *segment)
whether the given segment is 0 or encodes vaporization
Definition: MESegment.h:342
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:305
double getLength() const
Returns the length of the segment in meters.
Definition: MESegment.h:165
SUMOTime string2time(const std::string &r)
Definition: SUMOTime.cpp:47
std::map< SUMOTime, std::vector< MEVehicle * > > myLeaderCars
leader cars in the segments sorted by exit time
Definition: MELoop.h:147
T MIN2(T a, T b)
Definition: StdDefs.h:68
void registerTeleportJam()
register one non-collision-related teleport
static void setApproaching(MEVehicle *veh, MSLink *link)
registers vehicle with the given link
Definition: MELoop.cpp:212
bool moveRoutePointer()
Update when the vehicle enters a new edge in the move step.
Definition: MEVehicle.cpp:142
void scheduleVehicleRemoval(SUMOVehicle *veh)
Removes a vehicle after it has ended.
const MSEdge * succEdge(int nSuccs) const
Returns the nSuccs&#39;th successor of edge the vehicle is currently at.
int getNumericalID() const
Returns the numerical id of the edge.
Definition: MSEdge.h:260
SUMOTime getEventTime() const
Returns the (planned) time at which the next vehicle leaves this segment.
Definition: MESegment.cpp:625
A single mesoscopic segment (cell)
Definition: MESegment.h:57
bool hasSpaceFor(const MEVehicle *veh, SUMOTime entryTime, bool init=false) const
Returns whether the given vehicle would still fit into the segment.
Definition: MESegment.cpp:261
A storage for options typed value containers)
Definition: OptionsCont.h:99
virtual void activateReminders(const MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
"Activates" all current move reminder
const SUMOTime myLinkRecheckInterval
the interval at which to recheck at blocked junctions (<=0 means asap)
Definition: MELoop.h:156
void checkCar(MEVehicle *veh)
Check whether the vehicle may move.
Definition: MELoop.cpp:119
static SUMOTime gTimeToGridlock
Definition: MSGlobals.h:67
void setEventTime(SUMOTime t, bool hasDelay=true)
Sets the (planned) time at which the vehicle leaves his current cell.
Definition: MEVehicle.h:200
int getIndex() const
Returns the running index of the segment in the edge (0 is the most upstream).
Definition: MESegment.h:149
long long int SUMOTime
Definition: TraCIDefs.h:52
const MSEdge * getEdge() const
Returns the edge the vehicle is currently at.
bool mayProceed() const
Returns whether the vehicle is allowed to pass the next junction.
Definition: MEVehicle.cpp:272
static int numSegmentsFor(const double length, const double slength)
Compute number of segments per edge (best value stay close to the configured segment length) ...
Definition: MELoop.cpp:251
void send(MEVehicle *veh, MESegment *next, SUMOTime time)
Removes the vehicle from the segment, adapting its parameters.
Definition: MESegment.cpp:455
void simulate(SUMOTime tMax)
Perform simulation up to the given time.
Definition: MELoop.cpp:70
void addLeaderCar(MEVehicle *veh, MSLink *link)
Adds the given car to the leading vehicles.
Definition: MELoop.cpp:205
MESegment * getSegment() const
Returns the current segment the vehicle is on.
Definition: MEVehicle.h:230
const std::string & getID() const
Returns the name of the vehicle.