Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/microsim/MSEdgeControl.cpp
185785 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2001-2025 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 MSEdgeControl.cpp
15
/// @author Christian Roessel
16
/// @author Daniel Krajzewicz
17
/// @author Jakob Erdmann
18
/// @author Michael Behrisch
19
/// @date Mon, 09 Apr 2001
20
///
21
// Stores edges and lanes, performs moving of vehicle
22
/****************************************************************************/
23
#include <config.h>
24
25
#include <iostream>
26
#include <queue>
27
#include <vector>
28
#include "MSEdgeControl.h"
29
#include "MSVehicleControl.h"
30
#include "MSGlobals.h"
31
#include "MSEdge.h"
32
#include "MSLane.h"
33
#include "MSVehicle.h"
34
35
#define PARALLEL_PLAN_MOVE
36
#define PARALLEL_EXEC_MOVE
37
//#define PARALLEL_CHANGE_LANES
38
//#define LOAD_BALANCING
39
40
//#define PARALLEL_STOPWATCH
41
42
// ===========================================================================
43
// member method definitions
44
// ===========================================================================
45
MSEdgeControl::MSEdgeControl(const std::vector< MSEdge* >& edges)
46
: myEdges(edges),
47
myLanes(MSLane::dictSize()),
48
myWithVehicles2Integrate(MSGlobals::gNumSimThreads > 1),
49
myLastLaneChange(edges.size()),
50
myInactiveCheckCollisions(MSGlobals::gNumSimThreads > 1),
51
myMinLengthGeometryFactor(1.),
52
#ifdef THREAD_POOL
53
myThreadPool(false, std::vector<int>(MSGlobals::gNumThreads, 0)),
54
#endif
55
myStopWatch(3) {
56
// build the usage definitions for lanes
57
for (MSEdge* const edge : myEdges) {
58
const std::vector<MSLane*>& lanes = edge->getLanes();
59
if (!edge->hasLaneChanger()) {
60
const int pos = lanes.front()->getNumericalID();
61
myLanes[pos].lane = lanes.front();
62
myLanes[pos].amActive = false;
63
myLanes[pos].haveNeighbors = false;
64
myMinLengthGeometryFactor = MIN2(edge->getLengthGeometryFactor(), myMinLengthGeometryFactor);
65
} else {
66
for (MSLane* const l : lanes) {
67
const int pos = l->getNumericalID();
68
myLanes[pos].lane = l;
69
myLanes[pos].amActive = false;
70
myLanes[pos].haveNeighbors = true;
71
myMinLengthGeometryFactor = MIN2(l->getLengthGeometryFactor(), myMinLengthGeometryFactor);
72
}
73
myLastLaneChange[edge->getNumericalID()] = -1;
74
}
75
}
76
#ifndef THREAD_POOL
77
#ifdef HAVE_FOX
78
if (MSGlobals::gNumThreads > 1) {
79
while (myThreadPool.size() < MSGlobals::gNumThreads) {
80
new WorkerThread(myThreadPool);
81
}
82
}
83
#endif
84
#endif
85
}
86
87
88
MSEdgeControl::~MSEdgeControl() {
89
#ifndef THREAD_POOL
90
#ifdef HAVE_FOX
91
myThreadPool.clear();
92
#endif
93
#endif
94
#ifdef PARALLEL_STOPWATCH
95
StopWatch<std::chrono::nanoseconds> wPlan;
96
for (MSEdge* const edge : myEdges) {
97
for (MSLane* const l : edge->getLanes()) {
98
wPlan.add(l->getStopWatch()[0]);
99
}
100
}
101
std::cout << wPlan.getHistory().size() << " lane planmove calls, average " << wPlan.getAverage() << " ns, total " << wPlan.getTotal() / double(1e9) << " s" << std::endl;
102
std::cout << myStopWatch[0].getHistory().size() << " planmove calls, average " << myStopWatch[0].getAverage() << " ns, total " << myStopWatch[0].getTotal() / double(1e9) << " s" << std::endl;
103
std::cout << myStopWatch[1].getHistory().size() << " execmove calls, average " << myStopWatch[1].getAverage() << " ns, total " << myStopWatch[1].getTotal() / double(1e9) << " s" << std::endl;
104
#endif
105
}
106
107
void
108
MSEdgeControl::setActiveLanes(std::list<MSLane*> lanes) {
109
myActiveLanes = lanes;
110
for (MSLane* lane : lanes) {
111
myLanes[lane->getNumericalID()].amActive = true;
112
}
113
}
114
115
void
116
MSEdgeControl::patchActiveLanes() {
117
for (std::set<MSLane*, ComparatorNumericalIdLess>::iterator i = myChangedStateLanes.begin(); i != myChangedStateLanes.end(); ++i) {
118
LaneUsage& lu = myLanes[(*i)->getNumericalID()];
119
// if the lane was inactive but is now...
120
if (!lu.amActive && (*i)->getVehicleNumber() > 0) {
121
// ... add to active lanes and mark as such
122
if (lu.haveNeighbors) {
123
myActiveLanes.push_front(*i);
124
} else {
125
myActiveLanes.push_back(*i);
126
}
127
lu.amActive = true;
128
}
129
}
130
myChangedStateLanes.clear();
131
}
132
133
134
void
135
MSEdgeControl::planMovements(SUMOTime t) {
136
#ifdef PARALLEL_STOPWATCH
137
myStopWatch[0].start();
138
#endif
139
#ifdef THREAD_POOL
140
std::vector<std::future<void>> results;
141
#endif
142
for (std::list<MSLane*>::iterator i = myActiveLanes.begin(); i != myActiveLanes.end();) {
143
const int vehNum = (*i)->getVehicleNumber();
144
if (vehNum == 0) {
145
myLanes[(*i)->getNumericalID()].amActive = false;
146
i = myActiveLanes.erase(i);
147
} else {
148
#ifdef THREAD_POOL
149
if (MSGlobals::gNumSimThreads > 1) {
150
results.push_back(myThreadPool.executeAsync([i, t](int) {
151
(*i)->planMovements(t);
152
}, (*i)->getRNGIndex() % MSGlobals::gNumSimThreads));
153
++i;
154
continue;
155
}
156
#else
157
#ifdef HAVE_FOX
158
if (MSGlobals::gNumSimThreads > 1) {
159
myThreadPool.add((*i)->getPlanMoveTask(t), (*i)->getRNGIndex() % myThreadPool.size());
160
++i;
161
continue;
162
}
163
#endif
164
#endif
165
(*i)->planMovements(t);
166
++i;
167
}
168
}
169
#ifdef THREAD_POOL
170
for (auto& r : results) {
171
r.wait();
172
}
173
#else
174
#ifdef HAVE_FOX
175
if (MSGlobals::gNumSimThreads > 1) {
176
myThreadPool.waitAll(false);
177
}
178
#endif
179
#endif
180
#ifdef PARALLEL_STOPWATCH
181
myStopWatch[0].stop();
182
#endif
183
}
184
185
186
void
187
MSEdgeControl::setJunctionApproaches() {
188
for (MSLane* const lane : myActiveLanes) {
189
lane->setJunctionApproaches();
190
}
191
}
192
193
194
void
195
MSEdgeControl::executeMovements(SUMOTime t) {
196
#ifdef PARALLEL_STOPWATCH
197
myStopWatch[1].start();
198
#endif
199
std::vector<MSLane*> wasActive(myActiveLanes.begin(), myActiveLanes.end());
200
myWithVehicles2Integrate.clear();
201
#ifdef PARALLEL_EXEC_MOVE
202
#ifdef THREAD_POOL
203
if (MSGlobals::gNumSimThreads > 1) {
204
for (MSLane* const lane : myActiveLanes) {
205
myThreadPool.executeAsync([lane, t](int) {
206
lane->executeMovements(t);
207
}, lane->getRNGIndex() % MSGlobals::gNumSimThreads);
208
}
209
myThreadPool.waitAll();
210
}
211
#else
212
#ifdef HAVE_FOX
213
if (MSGlobals::gNumSimThreads > 1) {
214
for (MSLane* const lane : myActiveLanes) {
215
myThreadPool.add(lane->getExecuteMoveTask(t), lane->getRNGIndex() % myThreadPool.size());
216
}
217
myThreadPool.waitAll(false);
218
}
219
#endif
220
#endif
221
#endif
222
for (std::list<MSLane*>::iterator i = myActiveLanes.begin(); i != myActiveLanes.end();) {
223
if (
224
#ifdef PARALLEL_EXEC_MOVE
225
MSGlobals::gNumSimThreads <= 1 &&
226
#endif
227
(*i)->getVehicleNumber() > 0) {
228
(*i)->executeMovements(t);
229
}
230
if ((*i)->getVehicleNumber() == 0) {
231
myLanes[(*i)->getNumericalID()].amActive = false;
232
i = myActiveLanes.erase(i);
233
} else {
234
++i;
235
}
236
}
237
for (MSLane* lane : wasActive) {
238
lane->updateLengthSum();
239
}
240
// arrived vehicles should not influence lane changing
241
MSNet::getInstance()->getVehicleControl().removePending();
242
std::vector<MSLane*>& toIntegrate = myWithVehicles2Integrate.getContainer();
243
std::sort(toIntegrate.begin(), toIntegrate.end(), ComparatorIdLess());
244
/// @todo: sorting only needed to account for lane-ordering dependencies.
245
//This should disappear when parallelization is working. Until then it would
246
//be better to use ComparatorNumericalIdLess instead of ComparatorIdLess
247
myWithVehicles2Integrate.unlock();
248
for (MSLane* const lane : toIntegrate) {
249
const bool wasInactive = lane->getVehicleNumber() == 0;
250
lane->integrateNewVehicles();
251
if (wasInactive && lane->getVehicleNumber() > 0) {
252
LaneUsage& lu = myLanes[lane->getNumericalID()];
253
if (!lu.amActive) {
254
if (lu.haveNeighbors) {
255
myActiveLanes.push_front(lane);
256
} else {
257
myActiveLanes.push_back(lane);
258
}
259
lu.amActive = true;
260
}
261
}
262
}
263
#ifdef PARALLEL_STOPWATCH
264
myStopWatch[1].stop();
265
#endif
266
}
267
268
269
void
270
MSEdgeControl::changeLanes(const SUMOTime t) {
271
std::vector<MSLane*> toAdd;
272
#ifdef PARALLEL_CHANGE_LANES
273
std::vector<const MSEdge*> recheckLaneUsage;
274
#endif
275
MSGlobals::gComputeLC = true;
276
for (const MSLane* const l : myActiveLanes) {
277
if (myLanes[l->getNumericalID()].haveNeighbors) {
278
const MSEdge& edge = l->getEdge();
279
if (myLastLaneChange[edge.getNumericalID()] != t) {
280
myLastLaneChange[edge.getNumericalID()] = t;
281
#ifdef PARALLEL_CHANGE_LANES
282
if (MSGlobals::gNumSimThreads > 1) {
283
MSLane* lane = edge.getLanes()[0];
284
myThreadPool.add(lane->getLaneChangeTask(t), lane->getRNGIndex() % myThreadPool.size());
285
recheckLaneUsage.push_back(&edge);
286
} else {
287
#endif
288
edge.changeLanes(t);
289
for (MSLane* const lane : edge.getLanes()) {
290
LaneUsage& lu = myLanes[lane->getNumericalID()];
291
//if ((*i)->getID() == "disabled") {
292
// std::cout << SIMTIME << " vehicles=" << toString((*i)->getVehiclesSecure()) << "\n";
293
// (*i)->releaseVehicles();
294
//}
295
if (lane->getVehicleNumber() > 0 && !lu.amActive) {
296
toAdd.push_back(lane);
297
lu.amActive = true;
298
}
299
if (MSGlobals::gLateralResolution > 0) {
300
lane->sortManeuverReservations();
301
}
302
}
303
#ifdef PARALLEL_CHANGE_LANES
304
}
305
#endif
306
}
307
} else {
308
break;
309
}
310
}
311
312
#ifdef PARALLEL_CHANGE_LANES
313
if (MSGlobals::gNumSimThreads > 1) {
314
myThreadPool.waitAll(false);
315
for (const MSEdge* e : recheckLaneUsage) {
316
for (MSLane* const l : e->getLanes()) {
317
LaneUsage& lu = myLanes[l->getNumericalID()];
318
if (l->getVehicleNumber() > 0 && !lu.amActive) {
319
toAdd.push_back(l);
320
lu.amActive = true;
321
}
322
if (MSGlobals::gLateralResolution > 0) {
323
l->sortManeuverReservations();
324
}
325
}
326
}
327
}
328
#endif
329
330
MSGlobals::gComputeLC = false;
331
for (std::vector<MSLane*>::iterator i = toAdd.begin(); i != toAdd.end(); ++i) {
332
myActiveLanes.push_front(*i);
333
}
334
}
335
336
337
void
338
MSEdgeControl::detectCollisions(SUMOTime timestep, const std::string& stage) {
339
// Detections is made by the edge's lanes, therefore hand over.
340
for (MSLane* lane : myActiveLanes) {
341
if (lane->needsCollisionCheck()) {
342
lane->detectCollisions(timestep, stage);
343
}
344
}
345
if (myInactiveCheckCollisions.size() > 0) {
346
for (MSLane* lane : myInactiveCheckCollisions.getContainer()) {
347
lane->detectCollisions(timestep, stage);
348
}
349
myInactiveCheckCollisions.clear();
350
myInactiveCheckCollisions.unlock();
351
}
352
}
353
354
355
void
356
MSEdgeControl::gotActive(MSLane* l) {
357
myChangedStateLanes.insert(l);
358
}
359
360
void
361
MSEdgeControl::checkCollisionForInactive(MSLane* l) {
362
myInactiveCheckCollisions.insert(l);
363
}
364
365
void
366
MSEdgeControl::setAdditionalRestrictions() {
367
for (MSEdge* e : myEdges) {
368
e->inferEdgeType();
369
const std::vector<MSLane*>& lanes = e->getLanes();
370
for (std::vector<MSLane*>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
371
(*j)->initRestrictions();
372
}
373
}
374
}
375
376
void
377
MSEdgeControl::setMesoTypes() {
378
for (MSEdge* edge : myEdges) {
379
edge->updateMesoType();
380
}
381
}
382
383
void
384
MSEdgeControl::saveState(OutputDevice& out) {
385
out.openTag(SUMO_TAG_EDGECONTROL);
386
out.writeAttr(SUMO_ATTR_LANES, myActiveLanes);
387
out.closeTag();
388
}
389
390
/****************************************************************************/
391
392