Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 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 : /****************************************************************************/
14 : /// @file MELoop.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @date Tue, May 2005
17 : ///
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>
32 : #include <microsim/MSVehicleControl.h>
33 : #include <utils/options/OptionsCont.h>
34 : #include <utils/common/ToString.h>
35 : #include <utils/common/FileHelpers.h>
36 : #include <utils/common/SUMOTime.h>
37 : #include <utils/common/RandHelper.h>
38 : #include "MELoop.h"
39 : #include "MESegment.h"
40 : #include "MELSegment.h"
41 : #include "MEVehicle.h"
42 :
43 : long long int MELoop::LeaderEvent::myEventCounter(0);
44 :
45 : // ===========================================================================
46 : // method definitions
47 : // ===========================================================================
48 7038 : MELoop::MELoop(const SUMOTime recheckInterval) : myFullRecheckInterval(recheckInterval), myLinkRecheckInterval(TIME2STEPS(1)) {
49 7038 : }
50 :
51 6938 : MELoop::~MELoop() {
52 355463 : for (std::vector<MESegment*>::const_iterator j = myEdges2FirstSegments.begin(); j != myEdges2FirstSegments.end(); ++j) {
53 1071158 : for (MESegment* s = *j; s != nullptr;) {
54 : MESegment* n = s->getNextSegment();
55 722633 : delete s;
56 : s = n;
57 : }
58 : }
59 6938 : }
60 :
61 :
62 : void
63 23252575 : MELoop::simulate(SUMOTime tMax) {
64 63311093 : while (!myLeaderCars.empty()) {
65 53657652 : LeaderEvent e = myLeaderCars.top();
66 : assert(e.time > tMax - DELTA_T);
67 53657652 : if (e.time > tMax) {
68 : return;
69 : }
70 40058518 : myLeaderCars.pop();
71 40064797 : while (!myInvalidatedLeaderCars.empty() && e.time > myInvalidatedLeaderCars.top().time) {
72 6279 : myInvalidatedLeaderCars.pop();
73 : }
74 40058518 : if (!myInvalidatedLeaderCars.empty()) {
75 2257 : if (e == myInvalidatedLeaderCars.top()) {
76 2257 : myInvalidatedLeaderCars.pop();
77 : continue;
78 : }
79 : }
80 : //std::cout << SIMTIME << " checkChar " << e.veh->getID() << " on=" << e.veh->getSegment()->getID() << " t=" << e.time << " nid=" << e.veh->getNumericalID() << "\n";
81 40056261 : checkCar(e.veh);
82 : assert(myLeaderCars.empty() || myLeaderCars.top().time >= e.time);
83 : }
84 : }
85 :
86 :
87 : SUMOTime
88 40070863 : MELoop::changeSegment(MEVehicle* veh, SUMOTime leaveTime, MESegment* const toSegment, MSMoveReminder::Notification reason, const bool ignoreLink) const {
89 40070863 : int qIdx = 0;
90 : MESegment* const onSegment = veh->getSegment();
91 : if (MESegment::isInvalid(toSegment)) {
92 807893 : if (veh->isStoppedTriggered()) {
93 5398 : return leaveTime + MAX2(SUMOTime(1), myLinkRecheckInterval);
94 : }
95 802495 : if (onSegment != nullptr) {
96 798725 : onSegment->send(veh, toSegment, qIdx, leaveTime, reason);
97 : } else {
98 11310 : WRITE_WARNINGF(TL("Vehicle '%' teleports beyond arrival edge '%', time=%."),
99 : veh->getID(), veh->getEdge()->getID(), time2string(leaveTime));
100 : }
101 802495 : veh->setSegment(toSegment); // signal arrival
102 802495 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
103 802495 : return leaveTime;
104 39333125 : } else if (!MSGlobals::gCheckRoutes && !ignoreLink && !MESegment::isInvalid(onSegment) && &onSegment->getEdge() != &toSegment->getEdge() &&
105 30433 : veh->getEdge()->allowedLanes(*veh->succEdge(1), veh->getVClass()) == nullptr) {
106 27072 : if (veh->isStopped()) {
107 2 : veh->processStop();
108 : }
109 : return SUMOTime_MAX;
110 : }
111 39235898 : toSegment->updateEntryBlockTime(leaveTime);
112 39235898 : const SUMOTime entry = toSegment->hasSpaceFor(veh, leaveTime, qIdx);
113 39235898 : if (entry == leaveTime && (ignoreLink || veh->mayProceed())) {
114 25938737 : if (onSegment != nullptr) {
115 25938087 : if (veh->getQueIndex() == MESegment::PARKING_QUEUE) { // parking or just aborted parking
116 5651 : if (veh->isParking()) {
117 5650 : veh->processStop();
118 : }
119 5651 : veh->getEdge()->getLanes()[0]->removeParking(veh); // TODO for GUI only
120 : } else {
121 46800166 : onSegment->send(veh, toSegment, qIdx, leaveTime, onSegment->getNextSegment() == nullptr ? MSMoveReminder::NOTIFICATION_JUNCTION : MSMoveReminder::NOTIFICATION_SEGMENT);
122 : }
123 25938087 : toSegment->receive(veh, qIdx, leaveTime, false, ignoreLink, &onSegment->getEdge() != &toSegment->getEdge());
124 : } else {
125 1950 : WRITE_WARNINGF(TL("Vehicle '%' ends teleporting on edge '%':%, time=%."),
126 : veh->getID(), toSegment->getEdge().getID(), toSegment->getIndex(), time2string(leaveTime));
127 : // this is not quite correct but suffices for interrogation by
128 : // subsequent methods (veh->getSpeed() needs segment != 0)
129 650 : veh->setSegment(myEdges2FirstSegments[veh->getEdge()->getNumericalID()]);
130 : // clean up detectors (do not add traffic data)
131 : // note: updateDatector is not called if leaveTime == getLastEntryTime()
132 650 : veh->updateDetectors(veh->getLastEntryTime(), veh->getEventTime(), true, MSMoveReminder::NOTIFICATION_TELEPORT);
133 650 : toSegment->receive(veh, qIdx, leaveTime, false, true, true);
134 : }
135 25938737 : return entry;
136 : }
137 13297161 : if (entry == leaveTime && !ignoreLink) { // this is a long way of saying !veh->mayProceed() (which is a costly call)
138 10916456 : return entry + MAX2(SUMOTime(1), myLinkRecheckInterval);
139 : }
140 : return entry;
141 : }
142 :
143 :
144 : void
145 40056261 : MELoop::checkCar(MEVehicle* veh) {
146 : const SUMOTime leaveTime = veh->getEventTime();
147 : MESegment* const onSegment = veh->getSegment();
148 40056261 : MESegment* const toSegment = veh->getQueIndex() == MESegment::PARKING_QUEUE ? onSegment : nextSegment(onSegment, veh);
149 40056261 : const bool teleporting = (onSegment == nullptr); // is the vehicle currently teleporting?
150 : // @note reason is only evaluated if toSegment == nullptr
151 40056261 : const SUMOTime nextEntry = changeSegment(veh, leaveTime, toSegment, MSMoveReminder::NOTIFICATION_ARRIVED, teleporting);
152 40056261 : if (nextEntry == leaveTime) {
153 : return;
154 : }
155 13327409 : const bool r1 = MSGlobals::gTimeToGridlock > 0 && veh->getWaitingTime() > MSGlobals::gTimeToGridlock;
156 13327409 : const bool r3 = MSGlobals::gTimeToTeleportDisconnected >= 0 && veh->getWaitingTime() > MSGlobals::gTimeToTeleportDisconnected;
157 13327409 : if (!veh->isStopped() && (r1 || r3)) {
158 8596 : const bool disconnected = (MSGlobals::gTimeToTeleportDisconnected >= 0
159 1818 : && veh->succEdge(1) != nullptr
160 10414 : && veh->getEdge()->allowedLanes(*veh->succEdge(1), veh->getVClass()) == nullptr);
161 8596 : if ((r1 && !disconnected) || (r3 && disconnected)) {
162 6794 : teleportVehicle(veh, toSegment, disconnected);
163 6794 : return;
164 : }
165 : }
166 13320615 : if (veh->getBlockTime() == SUMOTime_MAX && (!veh->isStopped()
167 9919878 : || (!veh->isStoppedTriggered() && veh->isStoppedParking()))) {
168 : veh->setBlockTime(leaveTime);
169 : }
170 13320615 : if (nextEntry == SUMOTime_MAX) {
171 : // all usable queues on the next segment are full
172 2153000 : SUMOTime newEventTime = MAX3(toSegment->getEventTime() + 1, leaveTime + 1, leaveTime + myFullRecheckInterval);
173 2153000 : if (MSGlobals::gTimeToGridlock > 0) {
174 : // if teleporting is enabled, make sure we look at the vehicle when the gridlock-time is up
175 1655835 : const SUMOTime recheck = MSGlobals::gTimeToTeleportDisconnected >= 0 ? MIN2(MSGlobals::gTimeToGridlock, MSGlobals::gTimeToTeleportDisconnected) : MSGlobals::gTimeToGridlock;
176 1655835 : newEventTime = MAX2(MIN2(newEventTime, veh->getBlockTime() + recheck + 1), leaveTime + DELTA_T);
177 : }
178 : veh->setEventTime(newEventTime);
179 : } else {
180 : // receiving segment has recently received another vehicle or the junction is blocked
181 : veh->setEventTime(nextEntry);
182 : }
183 13320615 : addLeaderCar(veh, teleporting ? nullptr : onSegment->getLink(veh));
184 : }
185 :
186 :
187 : void
188 6794 : MELoop::teleportVehicle(MEVehicle* veh, MESegment* const toSegment, bool disconnected) {
189 : const SUMOTime leaveTime = veh->getEventTime();
190 : MESegment* const onSegment = veh->getSegment();
191 6794 : if (MSGlobals::gRemoveGridlocked) {
192 48 : WRITE_WARNINGF(TL("Teleporting vehicle '%'; waited too long, from edge '%':%, time=%."),
193 : veh->getID(), onSegment->getEdge().getID(), onSegment->getIndex(),
194 : time2string(leaveTime));
195 16 : MSNet::getInstance()->getVehicleControl().registerTeleportJam();
196 : int qIdx = 0;
197 16 : onSegment->send(veh, nullptr, qIdx, leaveTime, MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED);
198 16 : veh->setSegment(nullptr);
199 16 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
200 16 : return;
201 : }
202 : const bool teleporting = (onSegment == nullptr); // is the vehicle already teleporting?
203 : // try to find a place on the current edge
204 6778 : MESegment* teleSegment = disconnected ? toSegment : toSegment->getNextSegment();
205 9000 : while (teleSegment != nullptr && changeSegment(veh, leaveTime, teleSegment, MSMoveReminder::NOTIFICATION_TELEPORT, true) != leaveTime) {
206 : // @caution the time to get to the next segment here is ignored XXX
207 : teleSegment = teleSegment->getNextSegment();
208 : }
209 6778 : if (teleSegment != nullptr) {
210 382 : if (!teleporting) {
211 : // we managed to teleport in a single jump
212 746 : const std::string reason = disconnected ? " (disconnected)" : "";
213 1134 : WRITE_WARNINGF(TL("Teleporting vehicle '%'; waited too long%, from edge '%':% to edge '%':%, time=%."),
214 : veh->getID(), reason, onSegment->getEdge().getID(), onSegment->getIndex(),
215 : teleSegment->getEdge().getID(), teleSegment->getIndex(), time2string(leaveTime));
216 378 : MSNet::getInstance()->getVehicleControl().registerTeleportJam();
217 : }
218 : } else {
219 : // teleport across the current edge and try insertion later
220 6396 : if (!teleporting) {
221 : int qIdx = 0;
222 : // announce start of multi-step teleport, arrival will be announced in changeSegment()
223 13350 : WRITE_WARNINGF(TL("Teleporting vehicle '%'; waited too long, from edge '%':%, time=%."),
224 : veh->getID(), onSegment->getEdge().getID(), onSegment->getIndex(), time2string(leaveTime));
225 4450 : MSNet::getInstance()->getVehicleControl().registerTeleportJam();
226 : // remove from current segment
227 4450 : onSegment->send(veh, nullptr, qIdx, leaveTime, MSMoveReminder::NOTIFICATION_TELEPORT);
228 : // mark veh as teleporting
229 4450 : veh->setSegment(nullptr);
230 : } else {
231 1946 : veh->updateDetectors(veh->getLastEntryTime(), leaveTime, true, MSMoveReminder::NOTIFICATION_TELEPORT);
232 : }
233 : // @caution microsim uses current travel time teleport duration
234 19188 : const SUMOTime teleArrival = leaveTime + TIME2STEPS(veh->getEdge()->getLength() / MAX2(veh->getEdge()->getSpeedLimit(), NUMERICAL_EPS));
235 6396 : const bool atDest = veh->moveRoutePointer();
236 6396 : if (atDest) {
237 : // teleporting to end of route
238 3770 : changeSegment(veh, teleArrival, nullptr, MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED, true);
239 : } else {
240 : veh->setEventTime(teleArrival);
241 2626 : addLeaderCar(veh, nullptr);
242 : // teleporting vehicles must react to rerouters
243 2626 : getSegmentForEdge(*veh->getEdge())->addReminders(veh);
244 2626 : veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
245 : }
246 : }
247 : }
248 :
249 :
250 : void
251 40066020 : MELoop::addLeaderCar(MEVehicle* veh, MSLink* link) {
252 40066020 : myLeaderCars.push(LeaderEvent(veh));
253 40066020 : veh->setApproaching(link);
254 40066020 : }
255 :
256 :
257 : void
258 12 : MELoop::clearState() {
259 12 : myLeaderCars = LeaderEventQeue();
260 12 : myInvalidatedLeaderCars = LeaderEventQeue();
261 12 : }
262 :
263 :
264 : void
265 8568 : MELoop::removeLeaderCar(MEVehicle* v) {
266 8568 : myInvalidatedLeaderCars.push(LeaderEvent(v));
267 8568 : }
268 :
269 :
270 : void
271 0 : MELoop::vaporizeCar(MEVehicle* v, MSMoveReminder::Notification reason) {
272 : int qIdx = 0;
273 0 : v->getSegment()->send(v, nullptr, qIdx, MSNet::getInstance()->getCurrentTimeStep(), reason);
274 0 : removeLeaderCar(v);
275 0 : }
276 :
277 :
278 : MESegment*
279 39861328 : MELoop::nextSegment(MESegment* s, MEVehicle* v) {
280 39861328 : if (s != nullptr) { // vehicle is not teleporting
281 : MESegment* next = s->getNextSegment();
282 39858730 : if (next != nullptr) {
283 : // ok, the street continues
284 : return next;
285 : }
286 : }
287 : // we have to check the next edge in the vehicle's route
288 18391843 : const MSEdge* nextEdge = v->succEdge(1);
289 18391843 : if (nextEdge == nullptr) {
290 : // end of route
291 : return nullptr;
292 : }
293 17595948 : if (MSGlobals::gUsingInternalLanes && s != nullptr && s->getEdge().isNormal()) {
294 3407568 : const MSEdge* internal = s->getEdge().getInternalFollowingEdge(nextEdge, v->getVClass());
295 3407568 : if (internal) {
296 : nextEdge = internal;
297 : }
298 : }
299 17595948 : return myEdges2FirstSegments[nextEdge->getNumericalID()];
300 : }
301 :
302 :
303 : int
304 513538 : MELoop::numSegmentsFor(const double length, const double sLength) {
305 513538 : int no = (int)floor(length / sLength + 0.5);
306 513538 : if (no == 0) { // assure there is at least one segment
307 : return 1;
308 : } else {
309 202495 : return no;
310 : }
311 : }
312 :
313 :
314 : void
315 351037 : MELoop::buildSegmentsFor(const MSEdge& e, const OptionsCont& oc) {
316 351037 : const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(e.getEdgeType());
317 : const double length = e.getLength();
318 351037 : const int numSegments = numSegmentsFor(length, edgeType.edgeLength);
319 351037 : const double slength = length / (double)numSegments;
320 : MESegment* newSegment = nullptr;
321 : MESegment* nextSegment = nullptr;
322 351037 : const bool laneQueue = oc.getBool("meso-lane-queue");
323 351037 : const bool lift = oc.getBool("meso-ltm");
324 678678 : bool multiQueue = laneQueue || (oc.getBool("meso-multi-queue") && e.getLanes().size() > 1 && e.getNumSuccessors() > 1);
325 1078542 : for (int s = numSegments - 1; s >= 0; s--) {
326 1455010 : std::string id = e.getID() + ":" + toString(s);
327 : newSegment = lift
328 727505 : ? new MELSegment(id, e, nextSegment, slength, e.getLanes()[0]->getSpeedLimit(), s, multiQueue, edgeType)
329 727505 : : new MESegment(id, e, nextSegment, slength, e.getLanes()[0]->getSpeedLimit(), s, multiQueue, edgeType);
330 : multiQueue = laneQueue;
331 : nextSegment = newSegment;
332 : }
333 702074 : while (e.getNumericalID() >= static_cast<int>(myEdges2FirstSegments.size())) {
334 351037 : myEdges2FirstSegments.push_back(0);
335 : }
336 351037 : myEdges2FirstSegments[e.getNumericalID()] = newSegment;
337 752249 : for (MSLane* lane : e.getLanes()) {
338 401212 : lane->updateMesoGUISegments();
339 : }
340 351037 : }
341 :
342 :
343 : MESegment*
344 166770434 : MELoop::getSegmentForEdge(const MSEdge& e, double pos) {
345 166770434 : if (e.getNumericalID() >= (int)myEdges2FirstSegments.size()) {
346 : return nullptr;
347 : }
348 166770410 : MESegment* s = myEdges2FirstSegments[e.getNumericalID()];
349 166770410 : if (pos > 0) {
350 : double cpos = 0;
351 900701 : while (s->getNextSegment() != nullptr && cpos + s->getLength() < pos) {
352 : cpos += s->getLength();
353 : s = s->getNextSegment();
354 : }
355 : }
356 : return s;
357 : }
358 :
359 :
360 : bool
361 241097 : MELoop::isEnteringRoundabout(const MSEdge& e) {
362 654884 : for (const MSEdge* succ : e.getSuccessors()) {
363 413811 : if (succ->isRoundabout()) {
364 : return true;
365 : }
366 : }
367 : return false;
368 : }
369 :
370 :
371 40074588 : MELoop::LeaderEvent::LeaderEvent(MEVehicle* v):
372 40074588 : time(v->getEventTime()),
373 40074588 : eventIndex(myEventCounter++),
374 40074588 : nid(v->getNumericalID()),
375 40074588 : veh(v) { }
376 :
377 : /****************************************************************************/
|