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-2022 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>
38#include "MELoop.h"
39#include "MESegment.h"
40#include "MEVehicle.h"
41
42
43// ===========================================================================
44// method definitions
45// ===========================================================================
46MELoop::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
60void
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
79MELoop::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 (veh->isStoppedTriggered()) {
84 return leaveTime + MAX2(SUMOTime(1), myLinkRecheckInterval);
85 }
86 if (onSegment != nullptr) {
87 onSegment->send(veh, toSegment, qIdx, leaveTime, reason);
88 } else {
89 WRITE_WARNINGF(TL("Vehicle '%' teleports beyond arrival edge '%', time=%."),
90 veh->getID(), veh->getEdge()->getID(), time2string(leaveTime));
91 }
92 veh->setSegment(toSegment); // signal arrival
94 return leaveTime;
95 }
96 const SUMOTime entry = toSegment->hasSpaceFor(veh, leaveTime, qIdx);
97 if (entry == leaveTime && (ignoreLink || veh->mayProceed())) {
98 if (onSegment != nullptr) {
99 if (veh->getQueIndex() == MESegment::PARKING_QUEUE) { // parking or just aborted parking
100 if (veh->isParking()) {
101 veh->processStop();
102 }
103 veh->getEdge()->getLanes()[0]->removeParking(veh); // TODO for GUI only
104 } else {
105 onSegment->send(veh, toSegment, qIdx, leaveTime, onSegment->getNextSegment() == nullptr ? MSMoveReminder::NOTIFICATION_JUNCTION : MSMoveReminder::NOTIFICATION_SEGMENT);
106 }
107 toSegment->receive(veh, qIdx, leaveTime, false, ignoreLink, &onSegment->getEdge() != &toSegment->getEdge());
108 } else {
109 WRITE_WARNINGF(TL("Vehicle '%' ends teleporting on edge '%':%, time=%."),
110 veh->getID(), toSegment->getEdge().getID(), toSegment->getIndex(), time2string(leaveTime));
111 // this is not quite correct but suffices for interrogation by
112 // subsequent methods (veh->getSpeed() needs segment != 0)
114 // clean up detectors (do not add traffic data)
115 // note: updateDatector is not called if leaveTime == getLastEntryTime()
117 toSegment->receive(veh, qIdx, leaveTime, false, true, true);
118 }
119 return entry;
120 }
121 if (entry == leaveTime && !ignoreLink) { // this is a long way of saying !veh->mayProceed() (which is a costly call)
122 return entry + MAX2(SUMOTime(1), myLinkRecheckInterval);
123 }
124 return entry;
125}
126
127
128void
130 const SUMOTime leaveTime = veh->getEventTime();
131 MESegment* const onSegment = veh->getSegment();
132 MESegment* const toSegment = veh->getQueIndex() == MESegment::PARKING_QUEUE ? onSegment : nextSegment(onSegment, veh);
133 const bool teleporting = (onSegment == nullptr); // is the vehicle currently teleporting?
134 // @note reason is only evaluated if toSegment == nullptr
135 const SUMOTime nextEntry = changeSegment(veh, leaveTime, toSegment, MSMoveReminder::NOTIFICATION_ARRIVED, teleporting);
136 if (nextEntry == leaveTime) {
137 return;
138 }
140 teleportVehicle(veh, toSegment);
141 return;
142 }
143 if (veh->getBlockTime() == SUMOTime_MAX && !veh->isStopped()) {
144 veh->setBlockTime(leaveTime);
145 }
146 if (nextEntry == SUMOTime_MAX) {
147 // all usable queues on the next segment are full
148 SUMOTime newEventTime = MAX3(toSegment->getEventTime() + 1, leaveTime + 1, leaveTime + myFullRecheckInterval);
150 // if teleporting is enabled, make sure we look at the vehicle when the gridlock-time is up
151 newEventTime = MAX2(MIN2(newEventTime, veh->getBlockTime() + MSGlobals::gTimeToGridlock + 1), leaveTime + DELTA_T);
152 }
153 veh->setEventTime(newEventTime);
154 } else {
155 // receiving segment has recently received another vehicle or the junction is blocked
156 veh->setEventTime(nextEntry);
157 }
158 addLeaderCar(veh, onSegment->getLink(veh));
159}
160
161
162void
164 const SUMOTime leaveTime = veh->getEventTime();
165 MESegment* const onSegment = veh->getSegment();
166 const bool teleporting = (onSegment == nullptr); // is the vehicle already teleporting?
167 // try to find a place on the current edge
168 MESegment* teleSegment = toSegment->getNextSegment();
169 while (teleSegment != nullptr && changeSegment(veh, leaveTime, teleSegment, MSMoveReminder::NOTIFICATION_TELEPORT, true) != leaveTime) {
170 // @caution the time to get to the next segment here is ignored XXX
171 teleSegment = teleSegment->getNextSegment();
172 }
173 if (teleSegment != nullptr) {
174 if (!teleporting) {
175 // we managed to teleport in a single jump
176 WRITE_WARNINGF(TL("Teleporting vehicle '%'; waited too long, from edge '%':% to edge '%':%, time=%."),
177 veh->getID(), onSegment->getEdge().getID(), onSegment->getIndex(),
178 teleSegment->getEdge().getID(), teleSegment->getIndex(), time2string(leaveTime));
180 }
181 } else {
182 // teleport across the current edge and try insertion later
183 if (!teleporting) {
184 int qIdx = 0;
185 // announce start of multi-step teleport, arrival will be announced in changeSegment()
186 WRITE_WARNINGF(TL("Teleporting vehicle '%'; waited too long, from edge '%':%, time=%."),
187 veh->getID(), onSegment->getEdge().getID(), onSegment->getIndex(), time2string(leaveTime));
189 // remove from current segment
190 onSegment->send(veh, nullptr, qIdx, leaveTime, MSMoveReminder::NOTIFICATION_TELEPORT);
191 // mark veh as teleporting
192 veh->setSegment(nullptr);
193 }
194 // @caution microsim uses current travel time teleport duration
195 const SUMOTime teleArrival = leaveTime + TIME2STEPS(veh->getEdge()->getLength() / MAX2(veh->getEdge()->getSpeedLimit(), NUMERICAL_EPS));
196 const bool atDest = veh->moveRoutePointer();
197 if (atDest) {
198 // teleporting to end of route
199 changeSegment(veh, teleArrival, nullptr, MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED, true);
200 } else {
201 veh->setEventTime(teleArrival);
202 addLeaderCar(veh, nullptr);
203 // teleporting vehicles must react to rerouters
206 }
207 }
208}
209
210
211void
213 myLeaderCars[veh->getEventTime()].push_back(veh);
214 veh->setApproaching(link);
215}
216
217
218void
220 myLeaderCars.clear();
221}
222
223
224bool
226 const auto candIt = myLeaderCars.find(v->getEventTime());
227 if (candIt != myLeaderCars.end()) {
228 std::vector<MEVehicle*>& cands = candIt->second;
229 auto it = find(cands.begin(), cands.end(), v);
230 if (it != cands.end()) {
231 cands.erase(it);
232 return true;
233 }
234 }
235 return false;
236}
237
238
239void
241 int qIdx = 0;
242 v->getSegment()->send(v, nullptr, qIdx, MSNet::getInstance()->getCurrentTimeStep(), reason);
244}
245
246
249 if (s != nullptr) { // vehicle is not teleporting
250 MESegment* next = s->getNextSegment();
251 if (next != nullptr) {
252 // ok, the street continues
253 return next;
254 }
255 }
256 // we have to check the next edge in the vehicle's route
257 const MSEdge* nextEdge = v->succEdge(1);
258 if (nextEdge == nullptr) {
259 // end of route
260 return nullptr;
261 }
262 return myEdges2FirstSegments[nextEdge->getNumericalID()];
263}
264
265
266int
267MELoop::numSegmentsFor(const double length, const double sLength) {
268 int no = (int)floor(length / sLength + 0.5);
269 if (no == 0) { // assure there is at least one segment
270 return 1;
271 } else {
272 return no;
273 }
274}
275
276
277void
280 const double length = e.getLength();
281 const int numSegments = numSegmentsFor(length, oc.getFloat("meso-edgelength"));
282 const double slength = length / (double)numSegments;
283 MESegment* newSegment = nullptr;
284 MESegment* nextSegment = nullptr;
285 const bool laneQueue = oc.getBool("meso-lane-queue");
286 bool multiQueue = laneQueue || (oc.getBool("meso-multi-queue") && e.getLanes().size() > 1 && e.getNumSuccessors() > 1);
287 for (int s = numSegments - 1; s >= 0; s--) {
288 std::string id = e.getID() + ":" + toString(s);
289 newSegment = new MESegment(id, e, nextSegment, slength, e.getLanes()[0]->getSpeedLimit(), s, multiQueue, edgeType);
290 multiQueue = laneQueue;
291 nextSegment = newSegment;
292 }
293 while (e.getNumericalID() >= static_cast<int>(myEdges2FirstSegments.size())) {
294 myEdges2FirstSegments.push_back(0);
295 }
296 myEdges2FirstSegments[e.getNumericalID()] = newSegment;
297}
298
299
300void
302 if (e.getNumericalID() < (int)myEdges2FirstSegments.size()) {
305 while (s != nullptr) {
306 s->initSegment(edgeType, e, s->getCapacity());
307 s = s->getNextSegment();
308 }
309 }
310}
311
312
314MELoop::getSegmentForEdge(const MSEdge& e, double pos) {
315 if (e.getNumericalID() >= (int)myEdges2FirstSegments.size()) {
316 return nullptr;
317 }
319 if (pos > 0) {
320 double cpos = 0;
321 while (s->getNextSegment() != nullptr && cpos + s->getLength() < pos) {
322 cpos += s->getLength();
323 s = s->getNextSegment();
324 }
325 }
326 return s;
327}
328
329
330bool
332 for (const MSEdge* succ : e.getSuccessors()) {
333 if (succ->isRoundabout()) {
334 return true;
335 }
336 }
337 return false;
338}
339
340
341/****************************************************************************/
long long int SUMOTime
Definition: GUI.h:36
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:266
#define TL(string)
Definition: MsgHandler.h:282
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:33
#define TIME2STEPS(x)
Definition: SUMOTime.h:56
T MIN2(T a, T b)
Definition: StdDefs.h:71
T MAX2(T a, T b)
Definition: StdDefs.h:77
T MAX3(T a, T b, T c)
Definition: StdDefs.h:91
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
MESegment * nextSegment(MESegment *s, MEVehicle *v)
Retrieve next segment.
Definition: MELoop.cpp:248
static bool isEnteringRoundabout(const MSEdge &e)
whether the given edge is entering a roundabout
Definition: MELoop.cpp:331
void updateSegmentsForEdge(const MSEdge &e)
Update segments after loading meso edge type parameters from additional file.
Definition: MELoop.cpp:301
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:314
const SUMOTime myLinkRecheckInterval
the interval at which to recheck at blocked junctions (<=0 means asap)
Definition: MELoop.h:155
void simulate(SUMOTime tMax)
Perform simulation up to the given time.
Definition: MELoop.cpp:61
bool removeLeaderCar(MEVehicle *v)
Removes the given car from the leading vehicles.
Definition: MELoop.cpp:225
const SUMOTime myFullRecheckInterval
the interval at which to recheck at full segments (<=0 means asap)
Definition: MELoop.h:152
void vaporizeCar(MEVehicle *v, MSMoveReminder::Notification reason)
remove the given car and clean up the relevant data structures
Definition: MELoop.cpp:240
void teleportVehicle(MEVehicle *veh, MESegment *const toSegment)
teleports a vehicle or continues a teleport
Definition: MELoop.cpp:163
void addLeaderCar(MEVehicle *veh, MSLink *link)
Adds the given car to the leading vehicles.
Definition: MELoop.cpp:212
void clearState()
Remove all vehicles before quick-loading state.
Definition: MELoop.cpp:219
std::vector< MESegment * > myEdges2FirstSegments
mapping from internal edge ids to their initial segments
Definition: MELoop.h:149
std::map< SUMOTime, std::vector< MEVehicle * > > myLeaderCars
leader cars in the segments sorted by exit time
Definition: MELoop.h:146
~MELoop()
Definition: MELoop.cpp:49
void checkCar(MEVehicle *veh)
Check whether the vehicle may move.
Definition: MELoop.cpp:129
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:267
void buildSegmentsFor(const MSEdge &e, const OptionsCont &oc)
Build the segments for a given edge.
Definition: MELoop.cpp:278
A single mesoscopic segment (cell)
Definition: MESegment.h:49
void addReminders(MEVehicle *veh) const
add this lanes MoveReminders to the given vehicle
Definition: MESegment.cpp:563
static const int PARKING_QUEUE
Definition: MESegment.h:52
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:571
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:411
double getLength() const
Returns the length of the segment in meters.
Definition: MESegment.h:231
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:275
void initSegment(const MesoEdgeType &edgeType, const MSEdge &parent, const double capacity)
set model parameters (may be updated from additional file after network loading is complete)
Definition: MESegment.cpp:133
const MSEdge & getEdge() const
Returns the edge this segment belongs to.
Definition: MESegment.h:348
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:493
SUMOTime getEventTime() const
Returns the (planned) time at which the next vehicle leaves this segment.
Definition: MESegment.cpp:712
double getCapacity() const
Returns the sum of the lengths of all usable lanes of the segment in meters.
Definition: MESegment.h:239
int getIndex() const
Returns the running index of the segment in the edge (0 is the most upstream).
Definition: MESegment.h:215
static bool isInvalid(const MESegment *segment)
whether the given segment is 0 or encodes vaporization
Definition: MESegment.h:432
MESegment * getNextSegment() const
Returns the following segment on the same edge (0 if it is the last).
Definition: MESegment.h:223
A vehicle from the mesoscopic point of view.
Definition: MEVehicle.h:42
bool mayProceed()
Returns whether the vehicle is allowed to pass the next junction, checks also for triggered stops.
Definition: MEVehicle.cpp:344
void processStop()
ends the current stop and performs loading/unloading
Definition: MEVehicle.cpp:315
bool moveRoutePointer()
Update when the vehicle enters a new edge in the move step.
Definition: MEVehicle.cpp:140
void updateDetectors(SUMOTime currentTime, const bool isLeave, const MSMoveReminder::Notification reason=MSMoveReminder::NOTIFICATION_JUNCTION)
Updates all vehicle detectors.
Definition: MEVehicle.cpp:434
SUMOTime getLastEntryTime() const
Returns the time the vehicle entered the current segment.
Definition: MEVehicle.h:269
void setEventTime(SUMOTime t, bool hasDelay=true)
Sets the (planned) time at which the vehicle leaves his current cell.
Definition: MEVehicle.h:209
void setApproaching(MSLink *link)
registers vehicle with the given link
Definition: MEVehicle.cpp:180
MESegment * getSegment() const
Returns the current segment the vehicle is on.
Definition: MEVehicle.h:239
int getQueIndex() const
Returns the index of the que the vehicle is in.
Definition: MEVehicle.h:247
SUMOTime getWaitingTime() const
Returns the duration for which the vehicle was blocked.
Definition: MEVehicle.h:292
virtual void setSegment(MESegment *s, int idx=0)
Sets the current segment the vehicle is at together with its que.
Definition: MEVehicle.h:230
SUMOTime getEventTime() const
Returns the (planned) time at which the vehicle leaves his current cell.
Definition: MEVehicle.h:221
void setBlockTime(const SUMOTime t)
Sets the time at which the vehicle was blocked.
Definition: MEVehicle.h:277
SUMOTime getBlockTime() const
Returns the time at which the vehicle was blocked.
Definition: MEVehicle.h:286
const MSEdge * succEdge(int nSuccs) const
Returns the nSuccs'th successor of edge the vehicle is currently at.
bool isParking() const
Returns whether the vehicle is parking.
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
bool isStoppedTriggered() const
Returns whether the vehicle is on a triggered stop.
bool isStopped() const
Returns whether the vehicle is at a stop.
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:376
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:168
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:1056
double getLength() const
return the length of the edge
Definition: MSEdge.h:658
int getNumericalID() const
Returns the numerical id of the edge.
Definition: MSEdge.h:303
const std::string & getEdgeType() const
Returns the type of the edge.
Definition: MSEdge.h:316
const MSEdgeVector & getSuccessors(SUMOVehicleClass vClass=SVC_IGNORING) const
Returns the following edges, restricted by vClass.
Definition: MSEdge.cpp:1155
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:183
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:379
const MESegment::MesoEdgeType & getMesoType(const std::string &typeID)
Returns edge type specific meso parameters if no type specific parameters have been loaded,...
Definition: MSNet.cpp:363
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:74
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: MESegment.h:55