Eclipse 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-2020 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
18 // The main mesocopic simulation loop
19 /****************************************************************************/
20 #include <config.h>
21 
22 #include <queue>
23 #include <vector>
24 #include <map>
25 #include <cmath>
26 
27 #include <microsim/MSNet.h>
28 #include <microsim/MSEdge.h>
29 #include <microsim/MSGlobals.h>
30 #include <microsim/MSLane.h>
31 #include <microsim/MSVehicle.h>
34 #include <utils/common/ToString.h>
36 #include <utils/common/SUMOTime.h>
38 #include "MELoop.h"
39 #include "MESegment.h"
40 #include "MEVehicle.h"
41 
42 
43 // ===========================================================================
44 // method definitions
45 // ===========================================================================
46 MELoop::MELoop(const SUMOTime recheckInterval) : myFullRecheckInterval(recheckInterval), myLinkRecheckInterval(TIME2STEPS(1)) {
47 }
48 
50  for (std::vector<MESegment*>::const_iterator j = myEdges2FirstSegments.begin(); j != myEdges2FirstSegments.end(); ++j) {
51  for (MESegment* s = *j; s != nullptr;) {
52  MESegment* n = s->getNextSegment();
53  delete s;
54  s = n;
55  }
56  }
57 }
58 
59 
60 void
62  while (!myLeaderCars.empty()) {
63  const SUMOTime time = myLeaderCars.begin()->first;
64  std::vector<MEVehicle*> vehs = myLeaderCars[time];
65  assert(time > tMax - DELTA_T || vehs.size() == 0);
66  if (time > tMax) {
67  return;
68  }
69  myLeaderCars.erase(time);
70  for (std::vector<MEVehicle*>::const_iterator i = vehs.begin(); i != vehs.end(); ++i) {
71  checkCar(*i);
72  assert(myLeaderCars.empty() || myLeaderCars.begin()->first >= time);
73  }
74  }
75 }
76 
77 
79 MELoop::changeSegment(MEVehicle* veh, SUMOTime leaveTime, MESegment* const toSegment, MSMoveReminder::Notification reason, const bool ignoreLink) const {
80  int qIdx = 0;
81  MESegment* const onSegment = veh->getSegment();
82  if (MESegment::isInvalid(toSegment)) {
83  if (onSegment != nullptr) {
84  onSegment->send(veh, toSegment, qIdx, leaveTime, reason);
85  } else {
86  WRITE_WARNING("Vehicle '" + veh->getID() + "' teleports beyond arrival edge '" + veh->getEdge()->getID() + "', time " + time2string(leaveTime) + ".");
87  }
88  veh->setSegment(toSegment); // signal arrival
90  return leaveTime;
91  }
92  const SUMOTime entry = toSegment->hasSpaceFor(veh, leaveTime, qIdx);
93  if (entry == leaveTime && (ignoreLink || veh->mayProceed())) {
94  if (onSegment != nullptr) {
95  onSegment->send(veh, toSegment, qIdx, leaveTime, onSegment->getNextSegment() == nullptr ? MSMoveReminder::NOTIFICATION_JUNCTION : MSMoveReminder::NOTIFICATION_SEGMENT);
96  toSegment->receive(veh, qIdx, leaveTime, false, ignoreLink, &onSegment->getEdge() != &toSegment->getEdge());
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  // clean up detectors (do not add traffic data)
104  // note: updateDatector is not called if leaveTime == getLastEntryTime()
106  toSegment->receive(veh, qIdx, leaveTime, false, true, true);
107  }
108  return entry;
109  }
110  if (entry == leaveTime && !ignoreLink) { // this is a long way of saying !veh->mayProceed() (which is a costly call)
111  return entry + MAX2(SUMOTime(1), myLinkRecheckInterval);
112  }
113  return entry;
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 == nullptr); // is the vehicle currently teleporting?
123  // @note reason is only evaluated if toSegment == nullptr
124  const SUMOTime nextEntry = changeSegment(veh, leaveTime, toSegment, MSMoveReminder::NOTIFICATION_ARRIVED, teleporting);
125  if (nextEntry == leaveTime) {
126  return;
127  }
129  teleportVehicle(veh, toSegment);
130  return;
131  }
132  if (veh->getBlockTime() == SUMOTime_MAX) {
133  veh->setBlockTime(leaveTime);
134  }
135  if (nextEntry == SUMOTime_MAX) {
136  // all usable queues on the next segment are full
137  SUMOTime newEventTime = MAX3(toSegment->getEventTime() + 1, leaveTime + 1, leaveTime + myFullRecheckInterval);
138  if (MSGlobals::gTimeToGridlock > 0) {
139  // if teleporting is enabled, make sure we look at the vehicle when the the gridlock-time is up
140  newEventTime = MIN2(newEventTime, veh->getBlockTime() + MSGlobals::gTimeToGridlock + 1);
141  }
142  veh->setEventTime(newEventTime);
143  } else {
144  // receiving segment has recently received another vehicle or the junction is blocked
145  veh->setEventTime(nextEntry);
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 == nullptr); // is the vehicle already teleporting?
156  // try to find a place on the current edge
157  MESegment* teleSegment = toSegment->getNextSegment();
158  while (teleSegment != nullptr && changeSegment(veh, leaveTime, teleSegment, MSMoveReminder::NOTIFICATION_TELEPORT, true) != leaveTime) {
159  // @caution the time to get to the next segment here is ignored XXX
160  teleSegment = teleSegment->getNextSegment();
161  }
162  if (teleSegment != nullptr) {
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  } else {
173  // teleport across the current edge and try insertion later
174  if (!teleporting) {
175  int qIdx = 0;
176  // announce start of multi-step teleport, arrival will be announced in changeSegment()
177  WRITE_WARNING("Teleporting vehicle '" + veh->getID() + "'; waited too long, from edge '" + onSegment->getEdge().getID()
178  + "':" + toString(onSegment->getIndex()) + ", time " + time2string(leaveTime) + ".");
180  // remove from current segment
181  onSegment->send(veh, nullptr, qIdx, leaveTime, MSMoveReminder::NOTIFICATION_TELEPORT);
182  // mark veh as teleporting
183  veh->setSegment(nullptr);
184  }
185  // @caution microsim uses current travel time teleport duration
186  const SUMOTime teleArrival = leaveTime + TIME2STEPS(veh->getEdge()->getLength() / MAX2(veh->getEdge()->getSpeedLimit(), NUMERICAL_EPS));
187  const bool atDest = veh->moveRoutePointer();
188  if (atDest) {
189  // teleporting to end of route
190  changeSegment(veh, teleArrival, nullptr, MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED, true);
191  } else {
192  veh->setEventTime(teleArrival);
193  addLeaderCar(veh, nullptr);
194  // teleporting vehicles must react to rerouters
195  getSegmentForEdge(*veh->getEdge())->addReminders(veh);
197  }
198  }
199 }
200 
201 
202 void
204  myLeaderCars[veh->getEventTime()].push_back(veh);
205  veh->setApproaching(link);
206 }
207 
208 
209 void
211  myLeaderCars.clear();
212 }
213 
214 void
216  std::vector<MEVehicle*>& cands = myLeaderCars[v->getEventTime()];
217  auto it = find(cands.begin(), cands.end(), v);
218  if (it != cands.end()) {
219  cands.erase(it);
220  }
221 }
222 
223 void
225  int qIdx = 0;
226  v->getSegment()->send(v, nullptr, qIdx, MSNet::getInstance()->getCurrentTimeStep(), reason);
227  // try removeLeaderCar
228  std::vector<MEVehicle*>& cands = myLeaderCars[v->getEventTime()];
229  auto it = find(cands.begin(), cands.end(), v);
230  if (it != cands.end()) {
231  cands.erase(it);
232  }
233 }
234 
235 MESegment*
237  if (s != nullptr) { // vehicle is not teleporting
238  MESegment* next = s->getNextSegment();
239  if (next != nullptr) {
240  // ok, the street continues
241  return next;
242  }
243  }
244  // we have to check the next edge in the vehicle's route
245  const MSEdge* nextEdge = v->succEdge(1);
246  if (nextEdge == nullptr) {
247  // end of route
248  return nullptr;
249  }
250  return myEdges2FirstSegments[nextEdge->getNumericalID()];
251 }
252 
253 
254 int
255 MELoop::numSegmentsFor(const double length, const double sLength) {
256  int no = (int)floor(length / sLength + 0.5);
257  if (no == 0) { // assure there is at least one segment
258  return 1;
259  } else {
260  return no;
261  }
262 }
263 
264 
265 void
268  const double length = e.getLength();
269  const int numSegments = numSegmentsFor(length, oc.getFloat("meso-edgelength"));
270  const double slength = length / (double)numSegments;
271  MESegment* newSegment = nullptr;
272  MESegment* nextSegment = nullptr;
273  const bool laneQueue = oc.getBool("meso-lane-queue");
274  bool multiQueue = laneQueue || (oc.getBool("meso-multi-queue") && e.getLanes().size() > 1 && e.getNumSuccessors() > 1);
275  for (int s = numSegments - 1; s >= 0; s--) {
276  std::string id = e.getID() + ":" + toString(s);
277  newSegment = new MESegment(id, e, nextSegment, slength, e.getLanes()[0]->getSpeedLimit(), s, multiQueue, edgeType);
278  multiQueue = laneQueue;
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 void
290  if (e.getNumericalID() < (int)myEdges2FirstSegments.size()) {
293  while (s != nullptr) {
294  s->initSegment(edgeType, e);
295  s = s->getNextSegment();
296  }
297  }
298 }
299 
300 
301 MESegment*
302 MELoop::getSegmentForEdge(const MSEdge& e, double pos) {
303  if (e.getNumericalID() >= (int)myEdges2FirstSegments.size()) {
304  return nullptr;
305  }
307  if (pos > 0) {
308  double cpos = 0;
309  while (s->getNextSegment() != nullptr && cpos + s->getLength() < pos) {
310  cpos += s->getLength();
311  s = s->getNextSegment();
312  }
313  }
314  return s;
315 }
316 
317 
318 bool
320  for (const MSEdge* succ : e.getSuccessors()) {
321  if (succ->isRoundabout()) {
322  return true;
323  }
324  }
325  return false;
326 }
327 
328 
329 /****************************************************************************/
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:276
SUMOTime DELTA_T
Definition: SUMOTime.cpp:37
std::string time2string(SUMOTime t)
convert SUMOTime to string
Definition: SUMOTime.cpp:68
#define SUMOTime_MAX
Definition: SUMOTime.h:32
#define TIME2STEPS(x)
Definition: SUMOTime.h:55
long long int SUMOTime
Definition: SUMOTime.h:31
T MIN2(T a, T b)
Definition: StdDefs.h:73
T MAX2(T a, T b)
Definition: StdDefs.h:79
T MAX3(T a, T b, T c)
Definition: StdDefs.h:93
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:44
void updateSegementsForEdge(const MSEdge &e)
Update segments after loading meso edge type parameters from additional file.
Definition: MELoop.cpp:289
MESegment * nextSegment(MESegment *s, MEVehicle *v)
Retrieve next segment.
Definition: MELoop.cpp:236
static bool isEnteringRoundabout(const MSEdge &e)
whether the given edge is entering a roundabout
Definition: MELoop.cpp:319
MELoop(const SUMOTime recheckInterval)
SUMO constructor.
Definition: MELoop.cpp:46
SUMOTime changeSegment(MEVehicle *veh, SUMOTime leaveTime, MESegment *const toSegment, MSMoveReminder::Notification reason, const bool ignoreLink=false) const
change to the next segment this handles combinations of the following cases: (ending / continuing rou...
Definition: MELoop.cpp:79
MESegment * getSegmentForEdge(const MSEdge &e, double pos=0)
Get the segment for a given edge at a given position.
Definition: MELoop.cpp:302
const SUMOTime myLinkRecheckInterval
the interval at which to recheck at blocked junctions (<=0 means asap)
Definition: MELoop.h:154
void simulate(SUMOTime tMax)
Perform simulation up to the given time.
Definition: MELoop.cpp:61
const SUMOTime myFullRecheckInterval
the interval at which to recheck at full segments (<=0 means asap)
Definition: MELoop.h:151
void vaporizeCar(MEVehicle *v, MSMoveReminder::Notification reason)
remove the given car and clean up the relevant data structures
Definition: MELoop.cpp:224
void teleportVehicle(MEVehicle *veh, MESegment *const toSegment)
teleports a vehicle or continues a teleport
Definition: MELoop.cpp:152
void addLeaderCar(MEVehicle *veh, MSLink *link)
Adds the given car to the leading vehicles.
Definition: MELoop.cpp:203
void clearState()
Remove all vehicles before quick-loading state.
Definition: MELoop.cpp:210
void removeLeaderCar(MEVehicle *v)
Removes the given car from the leading vehicles.
Definition: MELoop.cpp:215
std::vector< MESegment * > myEdges2FirstSegments
mapping from internal edge ids to their initial segments
Definition: MELoop.h:148
std::map< SUMOTime, std::vector< MEVehicle * > > myLeaderCars
leader cars in the segments sorted by exit time
Definition: MELoop.h:145
~MELoop()
Definition: MELoop.cpp:49
void checkCar(MEVehicle *veh)
Check whether the vehicle may move.
Definition: MELoop.cpp:118
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:255
void buildSegmentsFor(const MSEdge &e, const OptionsCont &oc)
Build the segments for a given edge.
Definition: MELoop.cpp:266
A single mesoscopic segment (cell)
Definition: MESegment.h:47
void addReminders(MEVehicle *veh) const
add this lanes MoveReminders to the given vehicle
Definition: MESegment.cpp:538
void initSegment(const MSNet::MesoEdgeType &edgeType, const MSEdge &parent)
set model parameters (may be updated from additional file after network loading is complete)
Definition: MESegment.cpp:130
void receive(MEVehicle *veh, const int qIdx, SUMOTime time, const bool isDepart=false, const bool isTeleport=false, const bool newEdge=false)
Adds the vehicle to the segment, adapting its parameters.
Definition: MESegment.cpp:546
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:415
double getLength() const
Returns the length of the segment in meters.
Definition: MESegment.h:216
SUMOTime hasSpaceFor(const MEVehicle *const veh, const SUMOTime entryTime, int &qIdx, const bool init=false) const
Returns whether the given vehicle would still fit into the segment.
Definition: MESegment.cpp:283
MESegment * getNextSegment() const
Returns the following segment on the same edge (0 if it is the last).
Definition: MESegment.h:208
void send(MEVehicle *veh, MESegment *const next, const int nextQIdx, SUMOTime time, const MSMoveReminder::Notification reason)
Removes the vehicle from the segment, adapting its parameters.
Definition: MESegment.cpp:497
const MSEdge & getEdge() const
Returns the edge this segment belongs to.
Definition: MESegment.h:325
SUMOTime getEventTime() const
Returns the (planned) time at which the next vehicle leaves this segment.
Definition: MESegment.cpp:676
int getIndex() const
Returns the running index of the segment in the edge (0 is the most upstream).
Definition: MESegment.h:200
static bool isInvalid(const MESegment *segment)
whether the given segment is 0 or encodes vaporization
Definition: MESegment.h:409
A vehicle from the mesoscopic point of view.
Definition: MEVehicle.h:42
bool mayProceed() const
Returns whether the vehicle is allowed to pass the next junction.
Definition: MEVehicle.cpp:289
bool moveRoutePointer()
Update when the vehicle enters a new edge in the move step.
Definition: MEVehicle.cpp:139
void updateDetectors(SUMOTime currentTime, const bool isLeave, const MSMoveReminder::Notification reason=MSMoveReminder::NOTIFICATION_JUNCTION)
Updates all vehicle detectors.
Definition: MEVehicle.cpp:323
SUMOTime getLastEntryTime() const
Returns the time the vehicle entered the current segment.
Definition: MEVehicle.h:261
void setEventTime(SUMOTime t, bool hasDelay=true)
Sets the (planned) time at which the vehicle leaves his current cell.
Definition: MEVehicle.h:207
void setApproaching(MSLink *link)
registers vehicle with the given link
Definition: MEVehicle.cpp:179
MESegment * getSegment() const
Returns the current segment the vehicle is on.
Definition: MEVehicle.h:237
SUMOTime getWaitingTime() const
Returns the duration for which the vehicle was blocked.
Definition: MEVehicle.h:284
virtual void setSegment(MESegment *s, int idx=0)
Sets the current segment the vehicle is at together with its que.
Definition: MEVehicle.h:228
SUMOTime getEventTime() const
Returns the (planned) time at which the vehicle leaves his current cell.
Definition: MEVehicle.h:219
void setBlockTime(const SUMOTime t)
Sets the time at which the vehicle was blocked.
Definition: MEVehicle.h:269
SUMOTime getBlockTime() const
Returns the time at which the vehicle was blocked.
Definition: MEVehicle.h:278
const MSEdge * succEdge(int nSuccs) const
Returns the nSuccs'th successor of edge the vehicle is currently at.
const MSEdge * getEdge() const
Returns the edge the vehicle is currently at.
virtual void activateReminders(const MSMoveReminder::Notification reason, const MSLane *enteredLane=0)
"Activates" all current move reminder
A road/street connecting two junctions.
Definition: MSEdge.h:77
int getNumSuccessors() const
Returns the number of edges that may be reached from this edge.
Definition: MSEdge.h:353
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:166
double getSpeedLimit() const
Returns the speed limit of the edge @caution The speed limit of the first lane is retured; should pro...
Definition: MSEdge.cpp:919
double getLength() const
return the length of the edge
Definition: MSEdge.h:630
int getNumericalID() const
Returns the numerical id of the edge.
Definition: MSEdge.h:294
const std::string & getEdgeType() const
Returns the type of the edge.
Definition: MSEdge.h:307
const MSEdgeVector & getSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges, restricted by vClass.
Definition: MSEdge.cpp:1013
static SUMOTime gTimeToGridlock
Definition: MSGlobals.h:57
Notification
Definition of a vehicle state.
@ NOTIFICATION_ARRIVED
The vehicle arrived at its destination (is deleted)
@ NOTIFICATION_TELEPORT_ARRIVED
The vehicle was teleported out of the net.
@ NOTIFICATION_SEGMENT
The vehicle changes the segment (meso only)
@ NOTIFICATION_JUNCTION
The vehicle arrived at a junction.
@ NOTIFICATION_TELEPORT
The vehicle is being teleported.
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:171
const MesoEdgeType & getMesoType(const std::string &typeID)
Returns edge type specific meso parameters if no type specific parameters have been loaded,...
Definition: MSNet.cpp:347
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:371
void registerTeleportJam()
register one non-collision-related teleport
void scheduleVehicleRemoval(SUMOVehicle *veh, bool checkDuplicate=false)
Removes a vehicle after it has ended.
const std::string & getID() const
Returns the id.
Definition: Named.h:73
A storage for options typed value containers)
Definition: OptionsCont.h:89
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
edge type specific meso parameters
Definition: MSNet.h:117