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