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