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