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>
34 #include "MSGlobals.h"
35 #include "MSVehicle.h"
36 #include "MSVehicleControl.h"
37 #include "MSLane.h"
38 #include "MSEdge.h"
39 #include "MSNet.h"
40 #include "MSRouteHandler.h"
41 #include "MSInsertionControl.h"
42 
43 
44 // ===========================================================================
45 // member method definitions
46 // ===========================================================================
48  SUMOTime maxDepartDelay,
49  bool eagerInsertionCheck,
50  int maxVehicleNumber,
51  SUMOTime randomDepartOffset) :
52  myVehicleControl(vc),
53  myMaxDepartDelay(maxDepartDelay),
54  myEagerInsertionCheck(eagerInsertionCheck),
55  myMaxVehicleNumber(maxVehicleNumber),
56  myPendingEmitsUpdateTime(SUMOTime_MIN) {
57  myMaxRandomDepartOffset = randomDepartOffset;
59 }
60 
61 
63  for (std::vector<Flow>::iterator i = myFlows.begin(); i != myFlows.end(); ++i) {
64  delete(i->pars);
65  }
66 }
67 
68 
69 void
71  myAllVeh.add(veh);
72 }
73 
74 
75 bool
77  const bool loadingFromState = index >= 0;
78  if (myFlowIDs.count(pars->id) > 0) {
79  if (loadingFromState) {
80  // flows loaded from simulation state must be unique
81  return false;
82  }
83  // set actual parameters for a state-loaded flow (for which only index is known)
84  for (Flow& flow : myFlows) {
85  // if the flow was loaded from state this is recognizable by having
86  // neither repetitionNumber nor repetitionProbability
87  if (flow.pars->id == pars->id && flow.pars->repetitionNumber == -1 && flow.pars->repetitionProbability == -1) {
88  delete flow.pars;
89  flow.pars = pars;
90  return true;
91  }
92  }
93  return false;
94  } else {
95  Flow flow;
96  flow.pars = pars;
97  flow.index = loadingFromState ? index : 0;
98  myFlows.push_back(flow);
99  myFlowIDs.insert(pars->id);
100  return true;
101  }
102 }
103 
104 
105 int
107  // check whether any vehicles shall be emitted within this time step
108  const bool havePreChecked = MSDevice_Routing::isEnabled();
109  if (myPendingEmits.empty() || (havePreChecked && myEmitCandidates.empty())) {
110  return 0;
111  }
112  int numEmitted = 0;
113  // we use buffering for the refused emits to save time
114  // for this, we have two lists; one contains previously refused emits, the second
115  // will be used to append those vehicles that will not be able to depart in this
116  // time step
118 
119  // go through the list of previously refused vehicles, first
120  MSVehicleContainer::VehicleVector::const_iterator veh;
121  for (veh = myPendingEmits.begin(); veh != myPendingEmits.end(); veh++) {
122  if (havePreChecked && (myEmitCandidates.count(*veh) == 0)) {
123  refusedEmits.push_back(*veh);
124  } else {
125  numEmitted += tryInsert(time, *veh, refusedEmits);
126  }
127  }
128  myEmitCandidates.clear();
129  myPendingEmits = refusedEmits;
130  return numEmitted;
131 }
132 
133 
134 int
136  MSVehicleContainer::VehicleVector& refusedEmits) {
137  assert(veh->getParameter().depart < time + DELTA_T);
138  const MSEdge& edge = *veh->getEdge();
139  if (veh->isOnRoad()) {
140  return 1;
141  }
142  if ((myMaxVehicleNumber < 0 || (int)MSNet::getInstance()->getVehicleControl().getRunningVehicleNo() < myMaxVehicleNumber)
143  && edge.insertVehicle(*veh, time, false, myEagerInsertionCheck)) {
144  // Successful insertion
145  return 1;
146  }
147  if (myMaxDepartDelay >= 0 && time - veh->getParameter().depart > myMaxDepartDelay) {
148  // remove vehicles waiting too long for departure
149  myVehicleControl.deleteVehicle(veh, true);
150  } else if (edge.isVaporizing()) {
151  // remove vehicles if the edge shall be empty
152  myVehicleControl.deleteVehicle(veh, true);
153  } else if (myAbortedEmits.count(veh) > 0) {
154  // remove vehicles which shall not be inserted for some reason
155  myAbortedEmits.erase(veh);
156  myVehicleControl.deleteVehicle(veh, true);
157  } else {
158  // let the vehicle wait one step, we'll retry then
159  refusedEmits.push_back(veh);
160  }
161  edge.setLastFailedInsertionTime(time);
162  return 0;
163 }
164 
165 
166 void
167 MSInsertionControl::checkCandidates(SUMOTime time, const bool preCheck) {
168  while (myAllVeh.anyWaitingBefore(time + DELTA_T)) {
170  copy(top.begin(), top.end(), back_inserter(myPendingEmits));
171  myAllVeh.pop();
172  }
173  if (preCheck) {
174  MSVehicleContainer::VehicleVector::const_iterator veh;
175  for (veh = myPendingEmits.begin(); veh != myPendingEmits.end(); veh++) {
176  SUMOVehicle* const v = *veh;
177  const MSEdge* const edge = v->getEdge();
178  if (edge->insertVehicle(*v, time, true, myEagerInsertionCheck)) {
179  myEmitCandidates.insert(v);
180  } else {
181  MSDevice_Routing* dev = static_cast<MSDevice_Routing*>(v->getDevice(typeid(MSDevice_Routing)));
182  if (dev != 0) {
183  dev->skipRouting(time);
184  }
185  }
186  }
187  }
188 }
189 
190 
191 void
194  for (std::vector<Flow>::iterator i = myFlows.begin(); i != myFlows.end();) {
195  SUMOVehicleParameter* pars = i->pars;
196  bool tryEmitByProb = pars->repetitionProbability > 0;
197  while ((pars->repetitionProbability < 0
198  && pars->repetitionsDone < pars->repetitionNumber
199  && pars->depart + pars->repetitionsDone * pars->repetitionOffset < time + DELTA_T)
200  || (tryEmitByProb
201  && pars->depart < time + DELTA_T
202  && pars->repetitionEnd > time
203  // only call rand if all other conditions are met
205  ) {
206  tryEmitByProb = false; // only emit one per step
207  SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
208  newPars->id = pars->id + "." + toString(i->index);
209  newPars->depart = pars->repetitionProbability > 0 ? time : (SUMOTime)(pars->depart + pars->repetitionsDone * pars->repetitionOffset) + computeRandomDepartOffset();
210  pars->repetitionsDone++;
211  // try to build the vehicle
212  if (vehControl.getVehicle(newPars->id) == 0) {
213  const MSRoute* route = MSRoute::dictionary(pars->routeid);
214  MSVehicleType* vtype = vehControl.getVType(pars->vtypeid, MSRouteHandler::getParsingRNG());
215  SUMOVehicle* vehicle = vehControl.buildVehicle(newPars, route, vtype, !MSGlobals::gCheckRoutes);
216  int quota = vehControl.getQuota();
217  if (quota > 0) {
218  vehControl.addVehicle(newPars->id, vehicle);
219  add(vehicle);
220  i->index++;
221  while (--quota > 0) {
222  SUMOVehicleParameter* quotaPars = new SUMOVehicleParameter(*pars);
223  quotaPars->id = pars->id + "." + toString(i->index);
224  quotaPars->depart = pars->repetitionProbability > 0 ? time :
226  SUMOVehicle* vehicle = vehControl.buildVehicle(quotaPars, route, vtype, !MSGlobals::gCheckRoutes);
227  vehControl.addVehicle(quotaPars->id, vehicle);
228  add(vehicle);
229  i->index++;
230  }
231  } else {
232  vehControl.deleteVehicle(vehicle, true);
233  }
234  } else {
235  // strange: another vehicle with the same id already exists
237  vehControl.discountStateLoaded();
238  break;
239  }
240  throw ProcessError("Another vehicle with the id '" + newPars->id + "' exists.");
241  }
242  }
243  if (pars->repetitionsDone == pars->repetitionNumber || (pars->repetitionProbability > 0 && pars->repetitionEnd <= time)) {
244  i = myFlows.erase(i);
246  delete pars;
247  } else {
248  ++i;
249  }
250  }
252 }
253 
254 
255 int
257  return (int)myPendingEmits.size();
258 }
259 
260 
261 int
263  return (int)myFlows.size();
264 }
265 
266 
267 void
269  myAbortedEmits.insert(veh);
270 }
271 
272 
273 void
275  myPendingEmits.erase(std::remove(myPendingEmits.begin(), myPendingEmits.end(), veh), myPendingEmits.end());
276  myAllVeh.remove(veh);
277 }
278 
279 
280 void
281 MSInsertionControl::clearPendingVehicles(const std::string& route) {
282  //clear out the refused vehicle list, deleting the vehicles entirely
283  MSVehicleContainer::VehicleVector::iterator veh;
284  for (veh = myPendingEmits.begin(); veh != myPendingEmits.end();) {
285  if ((*veh)->getRoute().getID() == route || route == "") {
286  myVehicleControl.deleteVehicle(*veh, true);
287  veh = myPendingEmits.erase(veh);
288  } else {
289  ++veh;
290  }
291  }
292 }
293 
294 
295 int
297  if (MSNet::getInstance()->getCurrentTimeStep() > myPendingEmitsUpdateTime) {
298  // updated pending emits (only once per time step)
299  myPendingEmitsForLane.clear();
300  for (MSVehicleContainer::VehicleVector::const_iterator veh = myPendingEmits.begin(); veh != myPendingEmits.end(); ++veh) {
301  const MSLane* lane = (*veh)->getLane();
302  if (lane != 0) {
303  myPendingEmitsForLane[lane]++;
304  } else {
305  // no (tentative) departLane was set, increase count for all
306  // lanes of the depart edge
307  const MSEdge* edge = (*veh)->getEdge();
308  const std::vector<MSLane*>& lanes = edge->getLanes();
309  for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
310  myPendingEmitsForLane[*i]++;
311  }
312  }
313  }
315  }
316  return myPendingEmitsForLane[lane];
317 }
318 
319 
320 void
322  // fill the public transport router with pre-parsed public transport lines
323  for (const Flow& f : myFlows) {
324  if (f.pars->line != "") {
325  const MSRoute* route = MSRoute::dictionary(f.pars->routeid);
326  const std::vector<SUMOVehicleParameter::Stop>* addStops = 0;
327  if (route != 0) {
328  addStops = &route->getStops();
329  }
330  router.getNetwork()->addSchedule(*f.pars, addStops);
331  }
332  }
333 }
334 
335 
336 void
338  // save flow states
339  for (const Flow& flow : myFlows) {
341  out.writeAttr(SUMO_ATTR_ID, flow.pars->id);
342  out.writeAttr(SUMO_ATTR_INDEX, flow.index);
343  out.closeTag();
344  }
345 }
346 
347 
348 SUMOTime
350  if (myMaxRandomDepartOffset > 0) {
351  // round to the closest usable simulation step
353  } else {
354  return 0;
355  }
356 }
357 
358 
359 
360 /****************************************************************************/
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:526
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.
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:160
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:309
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:256
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.
static bool isEnabled()
returns whether any routing actions take place
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.
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.
virtual MSDevice * getDevice(const std::type_info &type) const =0
Returns a device of the given type if it exists or 0.
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:71
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:183
const std::vector< SUMOVehicleParameter::Stop > & getStops() const
Returns the stops.
Definition: MSRoute.cpp:360
void addSchedule(const SUMOVehicleParameter &pars, const std::vector< SUMOVehicleParameter::Stop > *addStops=0)
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
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:111