SUMO - Simulation of Urban MObility
MSInsertionControl.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-2018 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
19 // Inserts vehicles into the network when their departure time is reached
20 /****************************************************************************/
21 
22 
23 // ===========================================================================
24 // included modules
25 // ===========================================================================
26 #include <config.h>
27 
28 #include <iostream>
29 #include <algorithm>
30 #include <cassert>
31 #include <iterator>
35 #include "MSGlobals.h"
36 #include "MSVehicle.h"
37 #include "MSVehicleControl.h"
38 #include "MSLane.h"
39 #include "MSEdge.h"
40 #include "MSNet.h"
41 #include "MSRouteHandler.h"
42 #include "MSInsertionControl.h"
43 
44 
45 // ===========================================================================
46 // member method definitions
47 // ===========================================================================
49  SUMOTime maxDepartDelay,
50  bool eagerInsertionCheck,
51  int maxVehicleNumber,
52  SUMOTime randomDepartOffset) :
53  myVehicleControl(vc),
54  myMaxDepartDelay(maxDepartDelay),
55  myEagerInsertionCheck(eagerInsertionCheck),
56  myMaxVehicleNumber(maxVehicleNumber),
57  myPendingEmitsUpdateTime(SUMOTime_MIN) {
58  myMaxRandomDepartOffset = randomDepartOffset;
60 }
61 
62 
64  for (std::vector<Flow>::iterator i = myFlows.begin(); i != myFlows.end(); ++i) {
65  delete(i->pars);
66  }
67 }
68 
69 
70 void
72  myAllVeh.add(veh);
73 }
74 
75 
76 bool
78  const bool loadingFromState = index >= 0;
79  if (myFlowIDs.count(pars->id) > 0) {
80  if (loadingFromState) {
81  // flows loaded from simulation state must be unique
82  return false;
83  }
84  // set actual parameters for a state-loaded flow (for which only index is known)
85  for (Flow& flow : myFlows) {
86  // if the flow was loaded from state this is recognizable by having
87  // neither repetitionNumber nor repetitionProbability
88  if (flow.pars->id == pars->id && flow.pars->repetitionNumber == -1 && flow.pars->repetitionProbability == -1) {
89  delete flow.pars;
90  flow.pars = pars;
91  return true;
92  }
93  }
94  return false;
95  } else {
96  Flow flow;
97  flow.pars = pars;
98  flow.index = loadingFromState ? index : 0;
99  myFlows.push_back(flow);
100  myFlowIDs.insert(pars->id);
101  return true;
102  }
103 }
104 
105 
106 int
108  // check whether any vehicles shall be emitted within this time step
109  const bool havePreChecked = MSRoutingEngine::isEnabled();
110  if (myPendingEmits.empty() || (havePreChecked && myEmitCandidates.empty())) {
111  return 0;
112  }
113  int numEmitted = 0;
114  // we use buffering for the refused emits to save time
115  // for this, we have two lists; one contains previously refused emits, the second
116  // will be used to append those vehicles that will not be able to depart in this
117  // time step
119 
120  // go through the list of previously refused vehicles, first
121  MSVehicleContainer::VehicleVector::const_iterator veh;
122  for (veh = myPendingEmits.begin(); veh != myPendingEmits.end(); veh++) {
123  if (havePreChecked && (myEmitCandidates.count(*veh) == 0)) {
124  refusedEmits.push_back(*veh);
125  } else {
126  numEmitted += tryInsert(time, *veh, refusedEmits);
127  }
128  }
129  myEmitCandidates.clear();
130  myPendingEmits = refusedEmits;
131  return numEmitted;
132 }
133 
134 
135 int
137  MSVehicleContainer::VehicleVector& refusedEmits) {
138  assert(veh->getParameter().depart < time + DELTA_T);
139  const MSEdge& edge = *veh->getEdge();
140  if (veh->isOnRoad()) {
141  return 1;
142  }
143  if ((myMaxVehicleNumber < 0 || (int)MSNet::getInstance()->getVehicleControl().getRunningVehicleNo() < myMaxVehicleNumber)
144  && edge.insertVehicle(*veh, time, false, myEagerInsertionCheck)) {
145  // Successful insertion
146  return 1;
147  }
148  if (myMaxDepartDelay >= 0 && time - veh->getParameter().depart > myMaxDepartDelay) {
149  // remove vehicles waiting too long for departure
150  myVehicleControl.deleteVehicle(veh, true);
151  } else if (edge.isVaporizing()) {
152  // remove vehicles if the edge shall be empty
153  myVehicleControl.deleteVehicle(veh, true);
154  } else if (myAbortedEmits.count(veh) > 0) {
155  // remove vehicles which shall not be inserted for some reason
156  myAbortedEmits.erase(veh);
157  myVehicleControl.deleteVehicle(veh, true);
158  } else {
159  // let the vehicle wait one step, we'll retry then
160  refusedEmits.push_back(veh);
161  }
162  edge.setLastFailedInsertionTime(time);
163  return 0;
164 }
165 
166 
167 void
168 MSInsertionControl::checkCandidates(SUMOTime time, const bool preCheck) {
169  while (myAllVeh.anyWaitingBefore(time + DELTA_T)) {
171  copy(top.begin(), top.end(), back_inserter(myPendingEmits));
172  myAllVeh.pop();
173  }
174  if (preCheck) {
175  MSVehicleContainer::VehicleVector::const_iterator veh;
176  for (veh = myPendingEmits.begin(); veh != myPendingEmits.end(); veh++) {
177  SUMOVehicle* const v = *veh;
178  const MSEdge* const edge = v->getEdge();
179  if (edge->insertVehicle(*v, time, true, myEagerInsertionCheck)) {
180  myEmitCandidates.insert(v);
181  } else {
182  MSDevice_Routing* dev = static_cast<MSDevice_Routing*>(v->getDevice(typeid(MSDevice_Routing)));
183  if (dev != nullptr) {
184  dev->skipRouting(time);
185  }
186  }
187  }
188  }
189 }
190 
191 
192 void
195  for (std::vector<Flow>::iterator i = myFlows.begin(); i != myFlows.end();) {
196  SUMOVehicleParameter* pars = i->pars;
197  bool tryEmitByProb = pars->repetitionProbability > 0;
198  while ((pars->repetitionProbability < 0
199  && pars->repetitionsDone < pars->repetitionNumber
200  && pars->depart + pars->repetitionsDone * pars->repetitionOffset < time + DELTA_T)
201  || (tryEmitByProb
202  && pars->depart < time + DELTA_T
203  && pars->repetitionEnd > time
204  // only call rand if all other conditions are met
206  ) {
207  tryEmitByProb = false; // only emit one per step
208  SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
209  newPars->id = pars->id + "." + toString(i->index);
210  newPars->depart = pars->repetitionProbability > 0 ? time : (SUMOTime)(pars->depart + pars->repetitionsDone * pars->repetitionOffset) + computeRandomDepartOffset();
211  pars->repetitionsDone++;
212  // try to build the vehicle
213  if (vehControl.getVehicle(newPars->id) == nullptr) {
214  const MSRoute* route = MSRoute::dictionary(pars->routeid);
215  MSVehicleType* vtype = vehControl.getVType(pars->vtypeid, MSRouteHandler::getParsingRNG());
216  SUMOVehicle* vehicle = vehControl.buildVehicle(newPars, route, vtype, !MSGlobals::gCheckRoutes);
217  int quota = vehControl.getQuota();
218  if (quota > 0) {
219  vehControl.addVehicle(newPars->id, vehicle);
220  add(vehicle);
221  i->index++;
222  while (--quota > 0) {
223  SUMOVehicleParameter* quotaPars = new SUMOVehicleParameter(*pars);
224  quotaPars->id = pars->id + "." + toString(i->index);
225  quotaPars->depart = pars->repetitionProbability > 0 ? time :
227  SUMOVehicle* vehicle = vehControl.buildVehicle(quotaPars, route, vtype, !MSGlobals::gCheckRoutes);
228  vehControl.addVehicle(quotaPars->id, vehicle);
229  add(vehicle);
230  i->index++;
231  }
232  } else {
233  vehControl.deleteVehicle(vehicle, true);
234  }
235  } else {
236  // strange: another vehicle with the same id already exists
238  vehControl.discountStateLoaded();
239  break;
240  }
241  throw ProcessError("Another vehicle with the id '" + newPars->id + "' exists.");
242  }
243  }
244  if (pars->repetitionsDone == pars->repetitionNumber || (pars->repetitionProbability > 0 && pars->repetitionEnd <= time)) {
245  i = myFlows.erase(i);
247  delete pars;
248  } else {
249  ++i;
250  }
251  }
253 }
254 
255 
256 int
258  return (int)myPendingEmits.size();
259 }
260 
261 
262 int
264  return (int)myFlows.size();
265 }
266 
267 
268 void
270  myAbortedEmits.insert(veh);
271 }
272 
273 
274 void
276  myPendingEmits.erase(std::remove(myPendingEmits.begin(), myPendingEmits.end(), veh), myPendingEmits.end());
277  myAllVeh.remove(veh);
278 }
279 
280 
281 void
282 MSInsertionControl::clearPendingVehicles(const std::string& route) {
283  //clear out the refused vehicle list, deleting the vehicles entirely
284  MSVehicleContainer::VehicleVector::iterator veh;
285  for (veh = myPendingEmits.begin(); veh != myPendingEmits.end();) {
286  if ((*veh)->getRoute().getID() == route || route == "") {
287  myVehicleControl.deleteVehicle(*veh, true);
288  veh = myPendingEmits.erase(veh);
289  } else {
290  ++veh;
291  }
292  }
293 }
294 
295 
296 int
298  if (MSNet::getInstance()->getCurrentTimeStep() > myPendingEmitsUpdateTime) {
299  // updated pending emits (only once per time step)
300  myPendingEmitsForLane.clear();
301  for (MSVehicleContainer::VehicleVector::const_iterator veh = myPendingEmits.begin(); veh != myPendingEmits.end(); ++veh) {
302  const MSLane* lane = (*veh)->getLane();
303  if (lane != nullptr) {
304  myPendingEmitsForLane[lane]++;
305  } else {
306  // no (tentative) departLane was set, increase count for all
307  // lanes of the depart edge
308  const MSEdge* edge = (*veh)->getEdge();
309  const std::vector<MSLane*>& lanes = edge->getLanes();
310  for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
311  myPendingEmitsForLane[*i]++;
312  }
313  }
314  }
316  }
317  return myPendingEmitsForLane[lane];
318 }
319 
320 
321 void
323  // fill the public transport router with pre-parsed public transport lines
324  for (const Flow& f : myFlows) {
325  if (f.pars->line != "") {
326  const MSRoute* const route = MSRoute::dictionary(f.pars->routeid);
327  router.getNetwork()->addSchedule(*f.pars, route == nullptr ? nullptr : &route->getStops());
328  }
329  }
330 }
331 
332 
333 void
335  // save flow states
336  for (const Flow& flow : myFlows) {
338  out.writeAttr(SUMO_ATTR_ID, flow.pars->id);
339  out.writeAttr(SUMO_ATTR_INDEX, flow.index);
340  out.closeTag();
341  }
342 }
343 
344 
345 SUMOTime
347  if (myMaxRandomDepartOffset > 0) {
348  // round to the closest usable simulation step
350  } else {
351  return 0;
352  }
353 }
354 
355 
356 
357 /****************************************************************************/
std::map< const MSLane *, int > myPendingEmitsForLane
the number of pending emits for each edge in the current time step
void adaptIntermodalRouter(MSNet::MSIntermodalRouter &router) const
SUMOTime repetitionEnd
The time at which the flow ends (only needed when using repetitionProbability)
OutputDevice & writeAttr(const SumoXMLAttr attr, const T &val)
writes a named attribute
Definition: OutputDevice.h:256
void discountStateLoaded(bool removed=false)
avoid counting a vehicle twice if it was loaded from state and route input
bool insertVehicle(SUMOVehicle &v, SUMOTime time, const bool checkOnly=false, const bool forceCheck=false) const
Tries to insert the given vehicle into the network.
Definition: MSEdge.cpp:575
virtual void deleteVehicle(SUMOVehicle *v, bool discard=false)
Deletes the vehicle.
long long int SUMOTime
Definition: SUMOTime.h:36
void clearPendingVehicles(const std::string &route)
clears out all pending vehicles from a route, "" for all routes
void remove(SUMOVehicle *veh)
Removes a single vehicle.
int repetitionNumber
The number of times the vehicle shall be repeatedly inserted.
std::string vtypeid
The vehicle&#39;s type id.
virtual MSVehicleDevice * getDevice(const std::type_info &type) const =0
Returns a device of the given type if it exists or 0.
void checkCandidates(SUMOTime time, const bool preCheck)
Adds all vehicles that should have been emitted earlier to the refuse container.
Definition of vehicle flow with the current index for vehicle numbering.
double repetitionProbability
The probability for emitting a vehicle per second.
static double rand(std::mt19937 *rng=0)
Returns a random real number in [0, 1)
Definition: RandHelper.h:61
virtual const MSEdge * getEdge() const =0
Returns the edge the vehicle is currently at.
SUMOVehicle * getVehicle(const std::string &id) const
Returns the vehicle with the given id.
static bool gStateLoaded
Information whether a state has been loaded.
Definition: MSGlobals.h:88
A device that performs vehicle rerouting based on current edge speeds.
int repetitionsDone
The number of times the vehicle was already inserted.
int getQuota(double frac=-1) const
Returns the number of instances of the current vehicle that shall be emitted considering that "frac" ...
a flow state definition (used when saving and loading simulatino state)
MSVehicleContainer myAllVeh
All loaded vehicles sorted by their departure time.
const std::vector< MSLane * > & getLanes() const
Returns this edge&#39;s lanes.
Definition: MSEdge.h:162
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:165
SUMOTime DELTA_T
Definition: SUMOTime.cpp:35
virtual bool addVehicle(const std::string &id, SUMOVehicle *v)
Tries to insert the vehicle into the internal vehicle container.
void skipRouting(const SUMOTime currentTime)
Labels the current time step as "unroutable".
#define TS
Definition: SUMOTime.h:45
~MSInsertionControl()
Destructor.
bool anyWaitingBefore(SUMOTime time) const
Returns the information whether any vehicles want to depart before the given time.
SUMOTime repetitionOffset
The time offset between vehicle reinsertions.
The car-following model and parameter.
Definition: MSVehicleType.h:66
static std::mt19937 * getParsingRNG()
std::vector< SUMOVehicle * > VehicleVector
definition of a list of vehicles which have the same departure time
#define SUMOTime_MIN
Definition: SUMOTime.h:38
A road/street connecting two junctions.
Definition: MSEdge.h:75
void pop()
Removes the uppermost vehicle vector.
bool addFlow(SUMOVehicleParameter *const pars, int index=-1)
Adds parameter for a vehicle flow for departure.
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:49
std::string routeid
The vehicle&#39;s route id.
Representation of a vehicle.
Definition: SUMOVehicle.h:60
static bool gCheckRoutes
Definition: MSGlobals.h:79
int emitVehicles(SUMOTime time)
Emits vehicles that want to depart at the given time.
MSVehicleContainer::VehicleVector myPendingEmits
Buffers for vehicles that could not be inserted.
SUMOTime myMaxRandomDepartOffset
The maximum random offset to be added to vehicles departure times (non-negative)
int tryInsert(SUMOTime time, SUMOVehicle *veh, MSVehicleContainer::VehicleVector &refusedEmits)
Tries to emit the vehicle.
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:316
bool myEagerInsertionCheck
Whether an edge on which a vehicle could not depart should be ignored in the same step...
SUMOTime depart
The vehicle&#39;s departure time.
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:263
SUMOTime myMaxDepartDelay
The maximum waiting time; vehicles waiting longer are deleted (-1: no deletion)
virtual bool isOnRoad() const =0
Returns the information whether the vehicle is on a road (is simulated)
std::set< SUMOVehicle * > myEmitCandidates
Buffer for vehicles that may be inserted in the current step.
void add(SUMOVehicle *veh)
Adds a single vehicle.
SUMOTime myPendingEmitsUpdateTime
Last time at which pending emits for each edge where counted.
const VehicleVector & top()
Returns the uppermost vehicle vector.
std::vector< Flow > myFlows
Container for periodical vehicle parameters.
void alreadyDeparted(SUMOVehicle *veh)
stops trying to emit the given vehicle (because it already departed)
MSVehicleType * getVType(const std::string &id=DEFAULT_VTYPE_ID, std::mt19937 *rng=0)
Returns the named vehicle type or a sample from the named distribution.
std::mt19937 myFlowRNG
A random number generator for probabilistic flows.
int myMaxVehicleNumber
Storage for maximum vehicle number.
Structure representing possible vehicle parameter.
void addSchedule(const SUMOVehicleParameter &pars, const std::vector< SUMOVehicleParameter::Stop > *addStops=nullptr)
int getWaitingVehicleNo() const
Returns the number of waiting vehicles.
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle&#39;s parameter (including departure definition)
int getPendingFlowCount() const
Returns the number of flows that are still active.
MSVehicleControl & myVehicleControl
The assigned vehicle control (needed for vehicle re-insertion and deletion)
static void initRandGlobal(std::mt19937 *which=0)
Reads the given random number options and initialises the random number generator in accordance...
Definition: RandHelper.cpp:72
MSInsertionControl(MSVehicleControl &vc, SUMOTime maxDepartDelay, bool checkEdgesOnce, int maxVehicleNumber, SUMOTime randomDepartOffset)
Constructor.
Static storage of an output device and its base (abstract) implementation.
Definition: OutputDevice.h:64
bool closeTag(const std::string &comment="")
Closes the most recently opened tag and optionally adds a comment.
The class responsible for building and deletion of vehicles.
int index
the running index
SUMOVehicleParameter * pars
The parameters.
virtual SUMOVehicle * buildVehicle(SUMOVehicleParameter *defs, const MSRoute *route, MSVehicleType *type, const bool ignoreStopErrors, const bool fromRouteFile=true)
Builds a vehicle, increases the number of built vehicles.
SUMOTime computeRandomDepartOffset() const
compute (optional) random offset to the departure time
void saveState(OutputDevice &out)
Saves the current state into the given stream.
void add(SUMOVehicle *veh)
Adds a single vehicle for departure.
Representation of a lane in the micro simulation.
Definition: MSLane.h:78
std::set< const SUMOVehicle * > myAbortedEmits
Set of vehicles which shall not be inserted anymore.
std::set< std::string > myFlowIDs
Cache for periodical vehicle ids for quicker checking.
static void checkDist(const std::string &id)
Checks the distribution whether it is permanent and deletes it if not.
Definition: MSRoute.cpp:186
const std::vector< SUMOVehicleParameter::Stop > & getStops() const
Returns the stops.
Definition: MSRoute.cpp:366
void descheduleDeparture(const SUMOVehicle *veh)
stops trying to emit the given vehicle (and delete it)
int getPendingEmits(const MSLane *lane)
return the number of pending emits for the given lane
OutputDevice & openTag(const std::string &xmlElement)
Opens an XML tag.
void determineCandidates(SUMOTime time)
Checks for all vehicles whether they can be emitted.
Network * getNetwork() const
static bool isEnabled()
returns whether any routing actions take place
std::string id
The vehicle&#39;s id.
static bool dictionary(const std::string &id, const MSRoute *route)
Adds a route to the dictionary.
Definition: MSRoute.cpp:114