Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MELoop.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2023 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();
167 WRITE_WARNINGF(TL("Teleporting vehicle '%'; waited too long, from edge '%':%, time=%."),
168 veh->getID(), onSegment->getEdge().getID(), onSegment->getIndex(),
169 time2string(leaveTime));
171 int qIdx = 0;
172 onSegment->send(veh, nullptr, qIdx, leaveTime, MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED);
173 veh->setSegment(nullptr);
175 return;
176 }
177 const bool teleporting = (onSegment == nullptr); // is the vehicle already teleporting?
178 // try to find a place on the current edge
179 MESegment* teleSegment = toSegment->getNextSegment();
180 while (teleSegment != nullptr && changeSegment(veh, leaveTime, teleSegment, MSMoveReminder::NOTIFICATION_TELEPORT, true) != leaveTime) {
181 // @caution the time to get to the next segment here is ignored XXX
182 teleSegment = teleSegment->getNextSegment();
183 }
184 if (teleSegment != nullptr) {
185 if (!teleporting) {
186 // we managed to teleport in a single jump
187 WRITE_WARNINGF(TL("Teleporting vehicle '%'; waited too long, from edge '%':% to edge '%':%, time=%."),
188 veh->getID(), onSegment->getEdge().getID(), onSegment->getIndex(),
189 teleSegment->getEdge().getID(), teleSegment->getIndex(), time2string(leaveTime));
191 }
192 } else {
193 // teleport across the current edge and try insertion later
194 if (!teleporting) {
195 int qIdx = 0;
196 // announce start of multi-step teleport, arrival will be announced in changeSegment()
197 WRITE_WARNINGF(TL("Teleporting vehicle '%'; waited too long, from edge '%':%, time=%."),
198 veh->getID(), onSegment->getEdge().getID(), onSegment->getIndex(), time2string(leaveTime));
200 // remove from current segment
201 onSegment->send(veh, nullptr, qIdx, leaveTime, MSMoveReminder::NOTIFICATION_TELEPORT);
202 // mark veh as teleporting
203 veh->setSegment(nullptr);
204 }
205 // @caution microsim uses current travel time teleport duration
206 const SUMOTime teleArrival = leaveTime + TIME2STEPS(veh->getEdge()->getLength() / MAX2(veh->getEdge()->getSpeedLimit(), NUMERICAL_EPS));
207 const bool atDest = veh->moveRoutePointer();
208 if (atDest) {
209 // teleporting to end of route
210 changeSegment(veh, teleArrival, nullptr, MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED, true);
211 } else {
212 veh->setEventTime(teleArrival);
213 addLeaderCar(veh, nullptr);
214 // teleporting vehicles must react to rerouters
217 }
218 }
219}
220
221
222void
224 myLeaderCars[veh->getEventTime()].push_back(veh);
225 veh->setApproaching(link);
226}
227
228
229void
231 myLeaderCars.clear();
232}
233
234
235bool
237 const auto candIt = myLeaderCars.find(v->getEventTime());
238 if (candIt != myLeaderCars.end()) {
239 std::vector<MEVehicle*>& cands = candIt->second;
240 auto it = find(cands.begin(), cands.end(), v);
241 if (it != cands.end()) {
242 cands.erase(it);
243 return true;
244 }
245 }
246 return false;
247}
248
249
250void
252 int qIdx = 0;
253 v->getSegment()->send(v, nullptr, qIdx, MSNet::getInstance()->getCurrentTimeStep(), reason);
255}
256
257
260 if (s != nullptr) { // vehicle is not teleporting
261 MESegment* next = s->getNextSegment();
262 if (next != nullptr) {
263 // ok, the street continues
264 return next;
265 }
266 }
267 // we have to check the next edge in the vehicle's route
268 const MSEdge* nextEdge = v->succEdge(1);
269 if (nextEdge == nullptr) {
270 // end of route
271 return nullptr;
272 }
273 return myEdges2FirstSegments[nextEdge->getNumericalID()];
274}
275
276
277int
278MELoop::numSegmentsFor(const double length, const double sLength) {
279 int no = (int)floor(length / sLength + 0.5);
280 if (no == 0) { // assure there is at least one segment
281 return 1;
282 } else {
283 return no;
284 }
285}
286
287
288void
291 const double length = e.getLength();
292 const int numSegments = numSegmentsFor(length, oc.getFloat("meso-edgelength"));
293 const double slength = length / (double)numSegments;
294 MESegment* newSegment = nullptr;
295 MESegment* nextSegment = nullptr;
296 const bool laneQueue = oc.getBool("meso-lane-queue");
297 bool multiQueue = laneQueue || (oc.getBool("meso-multi-queue") && e.getLanes().size() > 1 && e.getNumSuccessors() > 1);
298 for (int s = numSegments - 1; s >= 0; s--) {
299 std::string id = e.getID() + ":" + toString(s);
300 newSegment = new MESegment(id, e, nextSegment, slength, e.getLanes()[0]->getSpeedLimit(), s, multiQueue, edgeType);
301 multiQueue = laneQueue;
302 nextSegment = newSegment;
303 }
304 while (e.getNumericalID() >= static_cast<int>(myEdges2FirstSegments.size())) {
305 myEdges2FirstSegments.push_back(0);
306 }
307 myEdges2FirstSegments[e.getNumericalID()] = newSegment;
308}
309
310
311void
313 if (e.getNumericalID() < (int)myEdges2FirstSegments.size()) {
316 while (s != nullptr) {
317 s->initSegment(edgeType, e, s->getCapacity());
318 s = s->getNextSegment();
319 }
320 }
321}
322
323
325MELoop::getSegmentForEdge(const MSEdge& e, double pos) {
326 if (e.getNumericalID() >= (int)myEdges2FirstSegments.size()) {
327 return nullptr;
328 }
330 if (pos > 0) {
331 double cpos = 0;
332 while (s->getNextSegment() != nullptr && cpos + s->getLength() < pos) {
333 cpos += s->getLength();
334 s = s->getNextSegment();
335 }
336 }
337 return s;
338}
339
340
341bool
343 for (const MSEdge* succ : e.getSuccessors()) {
344 if (succ->isRoundabout()) {
345 return true;
346 }
347 }
348 return false;
349}
350
351
352/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:271
#define TL(string)
Definition MsgHandler.h:287
SUMOTime DELTA_T
Definition SUMOTime.cpp:38
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:69
#define SUMOTime_MAX
Definition SUMOTime.h:34
#define TIME2STEPS(x)
Definition SUMOTime.h:57
T MIN2(T a, T b)
Definition StdDefs.h:76
T MAX2(T a, T b)
Definition StdDefs.h:82
T MAX3(T a, T b, T c)
Definition StdDefs.h:96
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:259
static bool isEnteringRoundabout(const MSEdge &e)
whether the given edge is entering a roundabout
Definition MELoop.cpp:342
void updateSegmentsForEdge(const MSEdge &e)
Update segments after loading meso edge type parameters from additional file.
Definition MELoop.cpp:312
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:325
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:236
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:251
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:223
void clearState()
Remove all vehicles before quick-loading state.
Definition MELoop.cpp:230
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:278
void buildSegmentsFor(const MSEdge &e, const OptionsCont &oc)
Build the segments for a given edge.
Definition MELoop.cpp:289
A single mesoscopic segment (cell)
Definition MESegment.h:49
void addReminders(MEVehicle *veh) const
add this lanes MoveReminders to the given vehicle
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.
MSLink * getLink(const MEVehicle *veh, bool tlsPenalty=false) const
Returns the link the given car will use when passing the next junction.
double getLength() const
Returns the length of the segment in meters.
Definition MESegment.h:242
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.
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)
const MSEdge & getEdge() const
Returns the edge this segment belongs to.
Definition MESegment.h:359
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.
SUMOTime getEventTime() const
Returns the (planned) time at which the next vehicle leaves this segment.
double getCapacity() const
Returns the sum of the lengths of all usable lanes of the segment in meters.
Definition MESegment.h:250
int getIndex() const
Returns the running index of the segment in the edge (0 is the most upstream).
Definition MESegment.h:226
static bool isInvalid(const MESegment *segment)
whether the given segment is 0 or encodes vaporization
Definition MESegment.h:443
MESegment * getNextSegment() const
Returns the following segment on the same edge (0 if it is the last).
Definition MESegment.h:234
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.
void processStop()
ends the current stop and performs loading/unloading
bool moveRoutePointer()
Update when the vehicle enters a new edge in the move step.
void updateDetectors(SUMOTime currentTime, const bool isLeave, const MSMoveReminder::Notification reason=MSMoveReminder::NOTIFICATION_JUNCTION)
Updates all vehicle detectors.
SUMOTime getLastEntryTime() const
Returns the time the vehicle entered the current segment.
Definition MEVehicle.h:248
void setEventTime(SUMOTime t, bool hasDelay=true)
Sets the (planned) time at which the vehicle leaves its current segment.
Definition MEVehicle.h:188
void setApproaching(MSLink *link)
registers vehicle with the given link
MESegment * getSegment() const
Returns the current segment the vehicle is on.
Definition MEVehicle.h:218
int getQueIndex() const
Returns the index of the que the vehicle is in.
Definition MEVehicle.h:226
SUMOTime getWaitingTime() const
Returns the duration for which the vehicle was blocked.
Definition MEVehicle.h:271
virtual void setSegment(MESegment *s, int idx=0)
Sets the current segment the vehicle is at together with its que.
Definition MEVehicle.h:209
SUMOTime getEventTime() const
Returns the (planned) time at which the vehicle leaves its current segment.
Definition MEVehicle.h:200
void setBlockTime(const SUMOTime t)
Sets the time at which the vehicle was blocked.
Definition MEVehicle.h:256
SUMOTime getBlockTime() const
Returns the time at which the vehicle was blocked.
Definition MEVehicle.h:265
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:1156
static bool gRemoveGridlocked
Definition MSGlobals.h:72
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:380
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:366
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