Eclipse SUMO - Simulation of Urban MObility
MSEdgeControl.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3// Copyright (C) 2001-2022 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/****************************************************************************/
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// ===========================================================================
45MSEdgeControl::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
89#ifndef THREAD_POOL
90#ifdef HAVE_FOX
91 myThreadPool.clear();
92#endif
93#endif
94#ifdef PARALLEL_STOPWATCH
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
107void
108MSEdgeControl::setActiveLanes(std::list<MSLane*> lanes) {
109 myActiveLanes = lanes;
110 for (MSLane* lane : lanes) {
111 myLanes[lane->getNumericalID()].amActive = true;
112 }
113}
114
115void
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
134void
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
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
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
176 myThreadPool.waitAll(false);
177 }
178#endif
179#endif
180#ifdef PARALLEL_STOPWATCH
181 myStopWatch[0].stop();
182#endif
183}
184
185
186void
188 for (MSLane* const lane : myActiveLanes) {
189 lane->setJunctionApproaches(t);
190 }
191}
192
193
194void
196#ifdef PARALLEL_STOPWATCH
197 myStopWatch[1].start();
198#endif
199 std::vector<MSLane*> wasActive(myActiveLanes.begin(), myActiveLanes.end());
201#ifdef PARALLEL_EXEC_MOVE
202#ifdef THREAD_POOL
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
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 (
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 }
241 std::vector<MSLane*>& toIntegrate = myWithVehicles2Integrate.getContainer();
242 std::sort(toIntegrate.begin(), toIntegrate.end(), ComparatorIdLess());
244 //This should disappear when parallelization is working. Until then it would
245 //be better to use ComparatorNumericalIdLess instead of ComparatorIdLess
247 for (MSLane* const lane : toIntegrate) {
248 const bool wasInactive = lane->getVehicleNumber() == 0;
249 lane->integrateNewVehicles();
250 if (wasInactive && lane->getVehicleNumber() > 0) {
251 LaneUsage& lu = myLanes[lane->getNumericalID()];
252 if (!lu.amActive) {
253 if (lu.haveNeighbors) {
254 myActiveLanes.push_front(lane);
255 } else {
256 myActiveLanes.push_back(lane);
257 }
258 lu.amActive = true;
259 }
260 }
261 }
262#ifdef PARALLEL_STOPWATCH
263 myStopWatch[1].stop();
264#endif
265}
266
267
268void
270 std::vector<MSLane*> toAdd;
271#ifdef PARALLEL_CHANGE_LANES
272 std::vector<const MSEdge*> recheckLaneUsage;
273#endif
275 for (const MSLane* const l : myActiveLanes) {
276 if (myLanes[l->getNumericalID()].haveNeighbors) {
277 const MSEdge& edge = l->getEdge();
278 if (myLastLaneChange[edge.getNumericalID()] != t) {
280#ifdef PARALLEL_CHANGE_LANES
282 MSLane* lane = edge.getLanes()[0];
283 myThreadPool.add(lane->getLaneChangeTask(t), lane->getRNGIndex() % myThreadPool.size());
284 recheckLaneUsage.push_back(&edge);
285 } else {
286#endif
287 edge.changeLanes(t);
288 for (MSLane* const lane : edge.getLanes()) {
289 LaneUsage& lu = myLanes[lane->getNumericalID()];
290 //if ((*i)->getID() == "disabled") {
291 // std::cout << SIMTIME << " vehicles=" << toString((*i)->getVehiclesSecure()) << "\n";
292 // (*i)->releaseVehicles();
293 //}
294 if (lane->getVehicleNumber() > 0 && !lu.amActive) {
295 toAdd.push_back(lane);
296 lu.amActive = true;
297 }
299 lane->sortManeuverReservations();
300 }
301 }
302#ifdef PARALLEL_CHANGE_LANES
303 }
304#endif
305 }
306 } else {
307 break;
308 }
309 }
310
311#ifdef PARALLEL_CHANGE_LANES
313 myThreadPool.waitAll(false);
314 for (const MSEdge* e : recheckLaneUsage) {
315 for (MSLane* const l : e->getLanes()) {
316 LaneUsage& lu = myLanes[l->getNumericalID()];
317 if (l->getVehicleNumber() > 0 && !lu.amActive) {
318 toAdd.push_back(l);
319 lu.amActive = true;
320 }
322 l->sortManeuverReservations();
323 }
324 }
325 }
326 }
327#endif
328
329 MSGlobals::gComputeLC = false;
330 for (std::vector<MSLane*>::iterator i = toAdd.begin(); i != toAdd.end(); ++i) {
331 myActiveLanes.push_front(*i);
332 }
333}
334
335
336void
337MSEdgeControl::detectCollisions(SUMOTime timestep, const std::string& stage) {
338 // Detections is made by the edge's lanes, therefore hand over.
339 for (MSLane* lane : myActiveLanes) {
340 if (lane->needsCollisionCheck()) {
341 lane->detectCollisions(timestep, stage);
342 }
343 }
346 lane->detectCollisions(timestep, stage);
347 }
350 }
351}
352
353
354void
356 myChangedStateLanes.insert(l);
357}
358
359void
362}
363
364void
366 for (MSEdge* e : myEdges) {
367 e->inferEdgeType();
368 const std::vector<MSLane*>& lanes = e->getLanes();
369 for (std::vector<MSLane*>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
370 (*j)->initRestrictions();
371 }
372 }
373}
374
375void
377 for (MSEdge* edge : myEdges) {
378 edge->updateMesoType();
379 }
380}
381
382void
386 out.closeTag();
387}
388
389/****************************************************************************/
long long int SUMOTime
Definition: GUI.h:36
#define PARALLEL_EXEC_MOVE
@ SUMO_TAG_EDGECONTROL
the internal state for edge control
@ SUMO_ATTR_LANES
T MIN2(T a, T b)
Definition: StdDefs.h:71
Container & getContainer()
Definition: MFXSynchQue.h:85
void unlock()
Definition: MFXSynchQue.h:100
void clear()
Definition: MFXSynchQue.h:143
void unlock()
Definition: MFXSynchSet.h:69
size_t size() const
Definition: MFXSynchSet.h:126
void clear()
Definition: MFXSynchSet.h:112
void insert(T what)
Definition: MFXSynchSet.h:83
Container & getContainer()
Definition: MFXSynchSet.h:54
void patchActiveLanes()
Resets information whether a lane is active for all lanes.
std::vector< StopWatch< std::chrono::nanoseconds > > myStopWatch
~MSEdgeControl()
Destructor.
void setMesoTypes()
update meso edge type parameters
void setActiveLanes(std::list< MSLane * > lanes)
Reconstruct the current state.
void setAdditionalRestrictions()
apply additional restrictions
std::list< MSLane * > myActiveLanes
The list of active (not empty) lanes.
void detectCollisions(SUMOTime timestep, const std::string &stage)
Detect collisions.
MFXSynchQue< MSLane *, std::vector< MSLane * > > myWithVehicles2Integrate
A storage for lanes which shall be integrated because vehicles have moved onto them.
MSEdgeVector myEdges
Loaded edges.
void setJunctionApproaches(SUMOTime t)
Register junction approaches for all vehicles after velocities have been planned. This is a prerequis...
void executeMovements(SUMOTime t)
Executes planned vehicle movements with regards to right-of-way.
MFXSynchSet< MSLane *, std::set< MSLane *, ComparatorNumericalIdLess > > myInactiveCheckCollisions
Additional lanes for which collision checking must be performed.
LaneUsageVector myLanes
Information about lanes' number of vehicles and neighbors.
void gotActive(MSLane *l)
Informs the control that the given lane got active.
void checkCollisionForInactive(MSLane *l)
trigger collision checking for inactive lane
std::vector< SUMOTime > myLastLaneChange
The list of active (not empty) lanes.
std::set< MSLane *, ComparatorNumericalIdLess > myChangedStateLanes
Lanes which changed the state without informing the control.
void planMovements(SUMOTime t)
Compute safe velocities for all vehicles based on positions and speeds from the last time step....
void saveState(OutputDevice &out)
Saves the current state into the given stream.
void changeLanes(const SUMOTime t)
Moves (precomputes) critical vehicles.
MSEdgeControl(const std::vector< MSEdge * > &edges)
Constructor.
double myMinLengthGeometryFactor
A road/street connecting two junctions.
Definition: MSEdge.h:77
void changeLanes(SUMOTime t) const
Performs lane changing on this edge.
Definition: MSEdge.cpp:790
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:168
int getNumericalID() const
Returns the numerical id of the edge.
Definition: MSEdge.h:303
static double gLateralResolution
Definition: MSGlobals.h:97
static bool gComputeLC
whether the simulationLoop is in the lane changing phase
Definition: MSGlobals.h:136
static int gNumSimThreads
how many threads to use for simulation
Definition: MSGlobals.h:142
static int gNumThreads
how many threads to use
Definition: MSGlobals.h:145
Representation of a lane in the micro simulation.
Definition: MSLane.h:84
int getRNGIndex() const
returns the associated RNG index
Definition: MSLane.h:240
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:379
void removePending()
Removes a vehicle after it has ended.
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:61
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:251
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
long long int getTotal() const
Definition: StopWatch.h:75
long long int getAverage() const
Definition: StopWatch.h:71
void add(const StopWatch< TimeT, ClockT > &other)
Definition: StopWatch.h:63
const std::vector< TimeT > & getHistory() const
Definition: StopWatch.h:67
Definition: json.hpp:4471
Function-object for stable sorting of objects acting like Named without being derived (SUMOVehicle)
Definition: Named.h:30
A structure holding some basic information about a simulated lane.
bool amActive
Information whether this lane is active.
bool haveNeighbors
Information whether this lane belongs to a multi-lane edge.