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.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 /****************************************************************************/
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 
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 
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
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
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
188  for (MSLane* const lane : myActiveLanes) {
189  lane->setJunctionApproaches(t);
190  }
191 }
192 
193 
194 void
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
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
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
242  std::vector<MSLane*>& toIntegrate = myWithVehicles2Integrate.getContainer();
243  std::sort(toIntegrate.begin(), toIntegrate.end(), ComparatorIdLess());
245  //This should disappear when parallelization is working. Until then it would
246  //be better to use ComparatorNumericalIdLess instead of ComparatorIdLess
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
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  }
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  }
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) {
347  lane->detectCollisions(timestep, stage);
348  }
351  }
352 }
353 
354 
355 void
357  myChangedStateLanes.insert(l);
358 }
359 
360 void
363 }
364 
365 void
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
378  for (MSEdge* edge : myEdges) {
379  edge->updateMesoType();
380  }
381 }
382 
383 void
387  out.closeTag();
388 }
389 
390 /****************************************************************************/
long long int SUMOTime
Definition: GUI.h:35
#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:76
void unlock()
Definition: MFXSynchQue.h:99
void clear()
Definition: MFXSynchQue.h:142
Container & getContainer()
Definition: MFXSynchQue.h:84
void unlock()
Definition: MFXSynchSet.h:68
size_t size() const
Definition: MFXSynchSet.h:154
void clear()
Definition: MFXSynchSet.h:140
Container & getContainer()
Definition: MFXSynchSet.h:53
void insert(T what)
Definition: MFXSynchSet.h:82
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:828
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:137
static int gNumSimThreads
how many threads to use for simulation
Definition: MSGlobals.h:143
static int gNumThreads
how many threads to use
Definition: MSGlobals.h:146
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:182
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:378
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 & openTag(const std::string &xmlElement)
Opens an XML tag.
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:254
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
const std::vector< TimeT > & getHistory() const
Definition: StopWatch.h:67
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
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.