Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
MSEdgeControl.cpp
Go to the documentation of this file.
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/****************************************************************************/
21// Stores edges and lanes, performs moving of vehicle
22/****************************************************************************/
23#include <config.h>
24
25#include <iostream>
26#include <queue>
27#include <vector>
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// ===========================================================================
47MSEdgeControl::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
91#ifndef THREAD_POOL
92#ifdef HAVE_FOX
93 myThreadPool.clear();
94#endif
95#endif
96#ifdef PARALLEL_STOPWATCH
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
109void
110MSEdgeControl::setActiveLanes(std::list<MSLane*> lanes) {
111 myActiveLanes = lanes;
112 for (MSLane* lane : lanes) {
113 myLanes[lane->getNumericalID()].amActive = true;
114 }
115}
116
117void
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
136void
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
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
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
178 myThreadPool.waitAll(false);
179 }
180#endif
181#endif
182#ifdef PARALLEL_STOPWATCH
183 myStopWatch[0].stop();
184#endif
185}
186
187
188void
190 for (MSLane* const lane : myActiveLanes) {
191 lane->setJunctionApproaches();
192 }
193}
194
195
196void
198#ifdef PARALLEL_STOPWATCH
199 myStopWatch[1].start();
200#endif
201 std::vector<MSLane*> wasActive(myActiveLanes.begin(), myActiveLanes.end());
203#ifdef PARALLEL_EXEC_MOVE
204#ifdef THREAD_POOL
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
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 (
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
244 std::vector<MSLane*>& toIntegrate = myWithVehicles2Integrate.getContainer();
245 std::sort(toIntegrate.begin(), toIntegrate.end(), ComparatorIdLess());
247 //This should disappear when parallelization is working. Until then it would
248 //be better to use ComparatorNumericalIdLess instead of ComparatorIdLess
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
271void
273 std::vector<MSLane*> toAdd;
274#ifdef PARALLEL_CHANGE_LANES
275 std::vector<const MSEdge*> recheckLaneUsage;
276#endif
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) {
283#ifdef PARALLEL_CHANGE_LANES
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 }
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
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 }
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
339void
340MSEdgeControl::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 }
349 lane->detectCollisions(timestep, stage);
350 }
353 }
354}
355
356
357void
361
362void
366
367void
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
378void
381 for (MSEdge* edge : myEdges) {
382 if (!edge->getLanes().empty()) {
384 }
385 }
386}
387
388void
394
395/****************************************************************************/
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:80
void buildSegmentsFor(const MSEdge &e, const OptionsCont &oc)
Build the segments for a given edge.
Definition MELoop.cpp:304
Container & getContainer()
Definition MFXSynchQue.h:84
void unlock()
Definition MFXSynchQue.h:99
void unlock()
Definition MFXSynchSet.h:68
size_t size() const
void insert(T what)
Definition MFXSynchSet.h:82
Container & getContainer()
Definition MFXSynchSet.h:53
void setJunctionApproaches()
Register junction approaches for all vehicles after velocities have been planned. This is a prerequis...
void patchActiveLanes()
Resets information whether a lane is active for all lanes.
std::vector< StopWatch< std::chrono::nanoseconds > > myStopWatch
~MSEdgeControl()
Destructor.
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 buildMesoSegments()
build meso segments after meso edge types are loaded
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:920
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:307
static MELoop * gMesoNet
mesoscopic simulation infrastructure
Definition MSGlobals.h:112
static double gLateralResolution
Definition MSGlobals.h:100
static bool gComputeLC
whether the simulationLoop is in the lane changing phase
Definition MSGlobals.h:140
static int gNumSimThreads
how many threads to use for simulation
Definition MSGlobals.h:146
static int gNumThreads
how many threads to use
Definition MSGlobals.h:149
Representation of a lane in the micro simulation.
Definition MSLane.h:84
int getRNGIndex() const
returns the associated RNG index
Definition MSLane.h:241
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:187
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition MSNet.h:392
void removePending()
Removes a vehicle after it has ended.
A storage for options typed value containers)
Definition OptionsCont.h:89
static OptionsCont & getOptions()
Retrieves the options.
Static storage of an output device and its base (abstract) implementation.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
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.