Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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 "MEVehicle.h"
41 :
42 :
43 : // ===========================================================================
44 : // method definitions
45 : // ===========================================================================
46 5198 : MELoop::MELoop(const SUMOTime recheckInterval) : myFullRecheckInterval(recheckInterval), myLinkRecheckInterval(TIME2STEPS(1)) {
47 5198 : }
48 :
49 5103 : MELoop::~MELoop() {
50 262688 : for (std::vector<MESegment*>::const_iterator j = myEdges2FirstSegments.begin(); j != myEdges2FirstSegments.end(); ++j) {
51 861494 : for (MESegment* s = *j; s != nullptr;) {
52 : MESegment* n = s->getNextSegment();
53 603909 : delete s;
54 : s = n;
55 : }
56 : }
57 5103 : }
58 :
59 :
60 : void
61 10516206 : MELoop::simulate(SUMOTime tMax) {
62 50604696 : while (!myLeaderCars.empty()) {
63 49378832 : const SUMOTime time = myLeaderCars.begin()->first;
64 49378832 : std::vector<MEVehicle*> vehs = myLeaderCars[time];
65 : assert(time > tMax - DELTA_T || vehs.size() == 0);
66 49378832 : if (time > tMax) {
67 : return;
68 : }
69 : myLeaderCars.erase(time);
70 82815160 : for (std::vector<MEVehicle*>::const_iterator i = vehs.begin(); i != vehs.end(); ++i) {
71 42726670 : checkCar(*i);
72 : assert(myLeaderCars.empty() || myLeaderCars.begin()->first >= time);
73 : }
74 : }
75 : }
76 :
77 :
78 : SUMOTime
79 42741983 : MELoop::changeSegment(MEVehicle* veh, SUMOTime leaveTime, MESegment* const toSegment, MSMoveReminder::Notification reason, const bool ignoreLink) const {
80 42741983 : int qIdx = 0;
81 : MESegment* const onSegment = veh->getSegment();
82 : if (MESegment::isInvalid(toSegment)) {
83 762980 : if (veh->isStoppedTriggered()) {
84 576 : return leaveTime + MAX2(SUMOTime(1), myLinkRecheckInterval);
85 : }
86 762404 : if (onSegment != nullptr) {
87 760744 : onSegment->send(veh, toSegment, qIdx, leaveTime, reason);
88 : } else {
89 4988 : WRITE_WARNINGF(TL("Vehicle '%' teleports beyond arrival edge '%', time=%."),
90 : veh->getID(), veh->getEdge()->getID(), time2string(leaveTime));
91 : }
92 762404 : veh->setSegment(toSegment); // signal arrival
93 762404 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
94 762404 : return leaveTime;
95 : }
96 41979003 : const SUMOTime entry = toSegment->hasSpaceFor(veh, leaveTime, qIdx);
97 41979003 : if (entry == leaveTime && (ignoreLink || veh->mayProceed())) {
98 32996449 : if (onSegment != nullptr) {
99 32995755 : if (veh->getQueIndex() == MESegment::PARKING_QUEUE) { // parking or just aborted parking
100 887 : if (veh->isParking()) {
101 711 : veh->processStop();
102 : }
103 887 : veh->getEdge()->getLanes()[0]->removeParking(veh); // TODO for GUI only
104 : } else {
105 62328000 : onSegment->send(veh, toSegment, qIdx, leaveTime, onSegment->getNextSegment() == nullptr ? MSMoveReminder::NOTIFICATION_JUNCTION : MSMoveReminder::NOTIFICATION_SEGMENT);
106 : }
107 32995755 : toSegment->receive(veh, qIdx, leaveTime, false, ignoreLink, &onSegment->getEdge() != &toSegment->getEdge());
108 : } else {
109 2120 : 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)
113 694 : veh->setSegment(myEdges2FirstSegments[veh->getEdge()->getNumericalID()]);
114 : // clean up detectors (do not add traffic data)
115 : // note: updateDatector is not called if leaveTime == getLastEntryTime()
116 694 : veh->updateDetectors(veh->getLastEntryTime(), true, MSMoveReminder::NOTIFICATION_TELEPORT);
117 694 : toSegment->receive(veh, qIdx, leaveTime, false, true, true);
118 : }
119 32996449 : return entry;
120 : }
121 8982554 : if (entry == leaveTime && !ignoreLink) { // this is a long way of saying !veh->mayProceed() (which is a costly call)
122 7408424 : return entry + MAX2(SUMOTime(1), myLinkRecheckInterval);
123 : }
124 : return entry;
125 : }
126 :
127 :
128 : void
129 42726670 : MELoop::checkCar(MEVehicle* veh) {
130 : const SUMOTime leaveTime = veh->getEventTime();
131 : MESegment* const onSegment = veh->getSegment();
132 42726670 : MESegment* const toSegment = veh->getQueIndex() == MESegment::PARKING_QUEUE ? onSegment : nextSegment(onSegment, veh);
133 42726670 : const bool teleporting = (onSegment == nullptr); // is the vehicle currently teleporting?
134 : // @note reason is only evaluated if toSegment == nullptr
135 42726670 : const SUMOTime nextEntry = changeSegment(veh, leaveTime, toSegment, MSMoveReminder::NOTIFICATION_ARRIVED, teleporting);
136 42726670 : if (nextEntry == leaveTime) {
137 : return;
138 : }
139 8978062 : if (!veh->isStopped() && MSGlobals::gTimeToGridlock > 0 && veh->getWaitingTime() > MSGlobals::gTimeToGridlock) {
140 4200 : teleportVehicle(veh, toSegment);
141 4200 : return;
142 : }
143 8973862 : if (veh->getBlockTime() == SUMOTime_MAX && !veh->isStopped()) {
144 : veh->setBlockTime(leaveTime);
145 : }
146 8973862 : if (nextEntry == SUMOTime_MAX) {
147 : // all usable queues on the next segment are full
148 1185634 : SUMOTime newEventTime = MAX3(toSegment->getEventTime() + 1, leaveTime + 1, leaveTime + myFullRecheckInterval);
149 1185634 : if (MSGlobals::gTimeToGridlock > 0) {
150 : // if teleporting is enabled, make sure we look at the vehicle when the gridlock-time is up
151 947497 : 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 8973862 : addLeaderCar(veh, onSegment->getLink(veh));
159 : }
160 :
161 :
162 : void
163 4200 : MELoop::teleportVehicle(MEVehicle* veh, MESegment* const toSegment) {
164 : const SUMOTime leaveTime = veh->getEventTime();
165 : MESegment* const onSegment = veh->getSegment();
166 4200 : if (MSGlobals::gRemoveGridlocked) {
167 48 : WRITE_WARNINGF(TL("Teleporting vehicle '%'; waited too long, from edge '%':%, time=%."),
168 : veh->getID(), onSegment->getEdge().getID(), onSegment->getIndex(),
169 : time2string(leaveTime));
170 16 : MSNet::getInstance()->getVehicleControl().registerTeleportJam();
171 : int qIdx = 0;
172 16 : onSegment->send(veh, nullptr, qIdx, leaveTime, MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED);
173 16 : veh->setSegment(nullptr);
174 16 : MSNet::getInstance()->getVehicleControl().scheduleVehicleRemoval(veh);
175 16 : 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 9252 : 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 4184 : if (teleSegment != nullptr) {
185 436 : if (!teleporting) {
186 : // we managed to teleport in a single jump
187 1238 : 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));
190 412 : MSNet::getInstance()->getVehicleControl().registerTeleportJam();
191 : }
192 : } else {
193 : // teleport across the current edge and try insertion later
194 3748 : if (!teleporting) {
195 : int qIdx = 0;
196 : // announce start of multi-step teleport, arrival will be announced in changeSegment()
197 7146 : WRITE_WARNINGF(TL("Teleporting vehicle '%'; waited too long, from edge '%':%, time=%."),
198 : veh->getID(), onSegment->getEdge().getID(), onSegment->getIndex(), time2string(leaveTime));
199 2366 : MSNet::getInstance()->getVehicleControl().registerTeleportJam();
200 : // remove from current segment
201 2366 : onSegment->send(veh, nullptr, qIdx, leaveTime, MSMoveReminder::NOTIFICATION_TELEPORT);
202 : // mark veh as teleporting
203 2366 : veh->setSegment(nullptr);
204 : }
205 : // @caution microsim uses current travel time teleport duration
206 11244 : const SUMOTime teleArrival = leaveTime + TIME2STEPS(veh->getEdge()->getLength() / MAX2(veh->getEdge()->getSpeedLimit(), NUMERICAL_EPS));
207 3748 : const bool atDest = veh->moveRoutePointer();
208 3748 : if (atDest) {
209 : // teleporting to end of route
210 1660 : changeSegment(veh, teleArrival, nullptr, MSMoveReminder::NOTIFICATION_TELEPORT_ARRIVED, true);
211 : } else {
212 : veh->setEventTime(teleArrival);
213 2088 : addLeaderCar(veh, nullptr);
214 : // teleporting vehicles must react to rerouters
215 2088 : getSegmentForEdge(*veh->getEdge())->addReminders(veh);
216 2088 : veh->activateReminders(MSMoveReminder::NOTIFICATION_JUNCTION);
217 : }
218 : }
219 : }
220 :
221 :
222 : void
223 42734270 : MELoop::addLeaderCar(MEVehicle* veh, MSLink* link) {
224 42734270 : myLeaderCars[veh->getEventTime()].push_back(veh);
225 42734270 : veh->setApproaching(link);
226 42734270 : }
227 :
228 :
229 : void
230 1 : MELoop::clearState() {
231 : myLeaderCars.clear();
232 1 : }
233 :
234 :
235 : bool
236 8641 : MELoop::removeLeaderCar(MEVehicle* v) {
237 8641 : const auto candIt = myLeaderCars.find(v->getEventTime());
238 8641 : if (candIt != myLeaderCars.end()) {
239 2492 : std::vector<MEVehicle*>& cands = candIt->second;
240 2492 : auto it = find(cands.begin(), cands.end(), v);
241 2492 : if (it != cands.end()) {
242 : cands.erase(it);
243 : return true;
244 : }
245 : }
246 : return false;
247 : }
248 :
249 :
250 : void
251 0 : MELoop::vaporizeCar(MEVehicle* v, MSMoveReminder::Notification reason) {
252 : int qIdx = 0;
253 0 : v->getSegment()->send(v, nullptr, qIdx, MSNet::getInstance()->getCurrentTimeStep(), reason);
254 0 : removeLeaderCar(v);
255 0 : }
256 :
257 :
258 : MESegment*
259 42644251 : MELoop::nextSegment(MESegment* s, MEVehicle* v) {
260 42644251 : if (s != nullptr) { // vehicle is not teleporting
261 : MESegment* next = s->getNextSegment();
262 42642175 : 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 12666604 : const MSEdge* nextEdge = v->succEdge(1);
269 12666604 : if (nextEdge == nullptr) {
270 : // end of route
271 : return nullptr;
272 : }
273 11913433 : return myEdges2FirstSegments[nextEdge->getNumericalID()];
274 : }
275 :
276 :
277 : int
278 375887 : MELoop::numSegmentsFor(const double length, const double sLength) {
279 375887 : int no = (int)floor(length / sLength + 0.5);
280 375887 : if (no == 0) { // assure there is at least one segment
281 : return 1;
282 : } else {
283 161140 : return no;
284 : }
285 : }
286 :
287 :
288 : void
289 260454 : MELoop::buildSegmentsFor(const MSEdge& e, const OptionsCont& oc) {
290 260454 : const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(e.getEdgeType());
291 : const double length = e.getLength();
292 260454 : const int numSegments = numSegmentsFor(length, oc.getFloat("meso-edgelength"));
293 260454 : const double slength = length / (double)numSegments;
294 : MESegment* newSegment = nullptr;
295 : MESegment* nextSegment = nullptr;
296 260454 : const bool laneQueue = oc.getBool("meso-lane-queue");
297 273371 : bool multiQueue = laneQueue || (oc.getBool("meso-multi-queue") && e.getLanes().size() > 1 && e.getNumSuccessors() > 1);
298 869345 : for (int s = numSegments - 1; s >= 0; s--) {
299 1217782 : std::string id = e.getID() + ":" + toString(s);
300 608891 : newSegment = new MESegment(id, e, nextSegment, slength, e.getLanes()[0]->getSpeedLimit(), s, multiQueue, edgeType);
301 : multiQueue = laneQueue;
302 : nextSegment = newSegment;
303 : }
304 520908 : while (e.getNumericalID() >= static_cast<int>(myEdges2FirstSegments.size())) {
305 260454 : myEdges2FirstSegments.push_back(0);
306 : }
307 260454 : myEdges2FirstSegments[e.getNumericalID()] = newSegment;
308 260454 : }
309 :
310 :
311 : void
312 160 : MELoop::updateSegmentsForEdge(const MSEdge& e) {
313 160 : if (e.getNumericalID() < (int)myEdges2FirstSegments.size()) {
314 160 : const MESegment::MesoEdgeType& edgeType = MSNet::getInstance()->getMesoType(e.getEdgeType());
315 160 : MESegment* s = myEdges2FirstSegments[e.getNumericalID()];
316 400 : while (s != nullptr) {
317 240 : s->initSegment(edgeType, e, s->getCapacity());
318 : s = s->getNextSegment();
319 : }
320 : }
321 160 : }
322 :
323 :
324 : MESegment*
325 59478781 : MELoop::getSegmentForEdge(const MSEdge& e, double pos) {
326 59478781 : if (e.getNumericalID() >= (int)myEdges2FirstSegments.size()) {
327 : return nullptr;
328 : }
329 59478761 : MESegment* s = myEdges2FirstSegments[e.getNumericalID()];
330 59478761 : if (pos > 0) {
331 : double cpos = 0;
332 781180 : while (s->getNextSegment() != nullptr && cpos + s->getLength() < pos) {
333 : cpos += s->getLength();
334 : s = s->getNextSegment();
335 : }
336 : }
337 : return s;
338 : }
339 :
340 :
341 : bool
342 195349 : MELoop::isEnteringRoundabout(const MSEdge& e) {
343 415830 : for (const MSEdge* succ : e.getSuccessors()) {
344 220493 : if (succ->isRoundabout()) {
345 : return true;
346 : }
347 : }
348 : return false;
349 : }
350 :
351 :
352 : /****************************************************************************/
|