Eclipse 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-2019 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  if (flow.pars->wasSet(VEHPARS_FORCE_REROUTE)) {
91  }
92  delete flow.pars;
93  flow.pars = pars;
94  return true;
95  }
96  }
97  return false;
98  } else {
99  Flow flow;
100  flow.pars = pars;
101  flow.index = loadingFromState ? index : 0;
102  myFlows.push_back(flow);
103  myFlowIDs.insert(pars->id);
104  return true;
105  }
106 }
107 
108 
109 int
111  // check whether any vehicles shall be emitted within this time step
112  const bool havePreChecked = MSRoutingEngine::isEnabled();
113  if (myPendingEmits.empty() || (havePreChecked && myEmitCandidates.empty())) {
114  return 0;
115  }
116  int numEmitted = 0;
117  // we use buffering for the refused emits to save time
118  // for this, we have two lists; one contains previously refused emits, the second
119  // will be used to append those vehicles that will not be able to depart in this
120  // time step
122 
123  // go through the list of previously refused vehicles, first
124  MSVehicleContainer::VehicleVector::const_iterator veh;
125  for (veh = myPendingEmits.begin(); veh != myPendingEmits.end(); veh++) {
126  if (havePreChecked && (myEmitCandidates.count(*veh) == 0)) {
127  refusedEmits.push_back(*veh);
128  } else {
129  numEmitted += tryInsert(time, *veh, refusedEmits);
130  }
131  }
132  myEmitCandidates.clear();
133  myPendingEmits = refusedEmits;
134  return numEmitted;
135 }
136 
137 
138 int
140  MSVehicleContainer::VehicleVector& refusedEmits) {
141  assert(veh->getParameter().depart < time + DELTA_T);
142  const MSEdge& edge = *veh->getEdge();
143  if (veh->isOnRoad()) {
144  return 1;
145  }
146  if ((myMaxVehicleNumber < 0 || (int)MSNet::getInstance()->getVehicleControl().getRunningVehicleNo() < myMaxVehicleNumber)
147  && edge.insertVehicle(*veh, time, false, myEagerInsertionCheck)) {
148  // Successful insertion
149  return 1;
150  }
151  if (myMaxDepartDelay >= 0 && time - veh->getParameter().depart > myMaxDepartDelay) {
152  // remove vehicles waiting too long for departure
153  myVehicleControl.deleteVehicle(veh, true);
154  } else if (edge.isVaporizing()) {
155  // remove vehicles if the edge shall be empty
156  myVehicleControl.deleteVehicle(veh, true);
157  } else if (myAbortedEmits.count(veh) > 0) {
158  // remove vehicles which shall not be inserted for some reason
159  myAbortedEmits.erase(veh);
160  myVehicleControl.deleteVehicle(veh, true);
161  } else {
162  // let the vehicle wait one step, we'll retry then
163  refusedEmits.push_back(veh);
164  }
165  edge.setLastFailedInsertionTime(time);
166  return 0;
167 }
168 
169 
170 void
171 MSInsertionControl::checkCandidates(SUMOTime time, const bool preCheck) {
172  while (myAllVeh.anyWaitingBefore(time + DELTA_T)) {
174  copy(top.begin(), top.end(), back_inserter(myPendingEmits));
175  myAllVeh.pop();
176  }
177  if (preCheck) {
178  MSVehicleContainer::VehicleVector::const_iterator veh;
179  for (veh = myPendingEmits.begin(); veh != myPendingEmits.end(); veh++) {
180  SUMOVehicle* const v = *veh;
181  const MSEdge* const edge = v->getEdge();
182  if (edge->insertVehicle(*v, time, true, myEagerInsertionCheck)) {
183  myEmitCandidates.insert(v);
184  } else {
185  MSDevice_Routing* dev = static_cast<MSDevice_Routing*>(v->getDevice(typeid(MSDevice_Routing)));
186  if (dev != nullptr) {
187  dev->skipRouting(time);
188  }
189  }
190  }
191  }
192 }
193 
194 
195 void
198  for (std::vector<Flow>::iterator i = myFlows.begin(); i != myFlows.end();) {
199  SUMOVehicleParameter* pars = i->pars;
200  bool tryEmitByProb = pars->repetitionProbability > 0;
201  while ((pars->repetitionProbability < 0
202  && pars->repetitionsDone < pars->repetitionNumber
203  && pars->depart + pars->repetitionsDone * pars->repetitionOffset < time + DELTA_T)
204  || (tryEmitByProb
205  && pars->depart < time + DELTA_T
206  && pars->repetitionEnd > time
207  // only call rand if all other conditions are met
209  ) {
210  tryEmitByProb = false; // only emit one per step
211  SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
212  newPars->id = pars->id + "." + toString(i->index);
213  newPars->depart = pars->repetitionProbability > 0 ? time : (SUMOTime)(pars->depart + pars->repetitionsDone * pars->repetitionOffset) + computeRandomDepartOffset();
214  pars->repetitionsDone++;
215  // try to build the vehicle
216  if (vehControl.getVehicle(newPars->id) == nullptr) {
217  const MSRoute* route = MSRoute::dictionary(pars->routeid);
218  MSVehicleType* vtype = vehControl.getVType(pars->vtypeid, MSRouteHandler::getParsingRNG());
219  SUMOVehicle* vehicle = vehControl.buildVehicle(newPars, route, vtype, !MSGlobals::gCheckRoutes);
220  int quota = vehControl.getQuota();
221  if (quota > 0) {
222  vehControl.addVehicle(newPars->id, vehicle);
223  add(vehicle);
224  i->index++;
225  while (--quota > 0) {
226  SUMOVehicleParameter* quotaPars = new SUMOVehicleParameter(*pars);
227  quotaPars->id = pars->id + "." + toString(i->index);
228  quotaPars->depart = pars->repetitionProbability > 0 ? time :
230  SUMOVehicle* vehicle = vehControl.buildVehicle(quotaPars, route, vtype, !MSGlobals::gCheckRoutes);
231  vehControl.addVehicle(quotaPars->id, vehicle);
232  add(vehicle);
233  i->index++;
234  }
235  } else {
236  vehControl.deleteVehicle(vehicle, true);
237  }
238  } else {
239  // strange: another vehicle with the same id already exists
241  vehControl.discountStateLoaded();
242  break;
243  }
244  throw ProcessError("Another vehicle with the id '" + newPars->id + "' exists.");
245  }
246  }
247  if (pars->repetitionsDone == pars->repetitionNumber || (pars->repetitionProbability > 0 && pars->repetitionEnd <= time)) {
248  i = myFlows.erase(i);
250  delete pars;
251  } else {
252  ++i;
253  }
254  }
256 }
257 
258 
259 int
261  return (int)myPendingEmits.size();
262 }
263 
264 
265 int
267  return (int)myFlows.size();
268 }
269 
270 
271 void
273  myAbortedEmits.insert(veh);
274 }
275 
276 
277 void
279  myPendingEmits.erase(std::remove(myPendingEmits.begin(), myPendingEmits.end(), veh), myPendingEmits.end());
280  myAllVeh.remove(veh);
281 }
282 
283 
284 void
285 MSInsertionControl::clearPendingVehicles(const std::string& route) {
286  //clear out the refused vehicle list, deleting the vehicles entirely
287  MSVehicleContainer::VehicleVector::iterator veh;
288  for (veh = myPendingEmits.begin(); veh != myPendingEmits.end();) {
289  if ((*veh)->getRoute().getID() == route || route == "") {
290  myVehicleControl.deleteVehicle(*veh, true);
291  veh = myPendingEmits.erase(veh);
292  } else {
293  ++veh;
294  }
295  }
296 }
297 
298 
299 int
301  if (MSNet::getInstance()->getCurrentTimeStep() > myPendingEmitsUpdateTime) {
302  // updated pending emits (only once per time step)
303  myPendingEmitsForLane.clear();
304  for (MSVehicleContainer::VehicleVector::const_iterator veh = myPendingEmits.begin(); veh != myPendingEmits.end(); ++veh) {
305  const MSLane* lane = (*veh)->getLane();
306  if (lane != nullptr) {
307  myPendingEmitsForLane[lane]++;
308  } else {
309  // no (tentative) departLane was set, increase count for all
310  // lanes of the depart edge
311  const MSEdge* edge = (*veh)->getEdge();
312  const std::vector<MSLane*>& lanes = edge->getLanes();
313  for (std::vector<MSLane*>::const_iterator i = lanes.begin(); i != lanes.end(); ++i) {
314  myPendingEmitsForLane[*i]++;
315  }
316  }
317  }
319  }
320  return myPendingEmitsForLane[lane];
321 }
322 
323 
324 void
326  // fill the public transport router with pre-parsed public transport lines
327  for (const Flow& f : myFlows) {
328  if (f.pars->line != "") {
329  const MSRoute* const route = MSRoute::dictionary(f.pars->routeid);
330  router.getNetwork()->addSchedule(*f.pars, route == nullptr ? nullptr : &route->getStops());
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  if (flow.pars->wasSet(VEHPARS_FORCE_REROUTE)) {
344  out.writeAttr(SUMO_ATTR_REROUTE, true);
345  }
346  out.closeTag();
347  }
348 }
349 
350 
351 SUMOTime
353  if (myMaxRandomDepartOffset > 0) {
354  // round to the closest usable simulation step
356  } else {
357  return 0;
358  }
359 }
360 
361 
362 
363 /****************************************************************************/
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:583
virtual void deleteVehicle(SUMOVehicle *v, bool discard=false)
Deletes the vehicle.
long long int SUMOTime
Definition: SUMOTime.h:35
const int VEHPARS_FORCE_REROUTE
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.
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.
MSVehicleType * getVType(const std::string &id=DEFAULT_VTYPE_ID, std::mt19937 *rng=nullptr)
Returns the named vehicle type or a sample from the named distribution.
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:60
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
int parametersSet
Information for the router which parameter were set, TraCI may modify this (whe changing color) ...
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:165
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:168
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:44
~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()
get parsing RNG
std::vector< SUMOVehicle * > VehicleVector
definition of a list of vehicles which have the same departure time
#define SUMOTime_MIN
Definition: SUMOTime.h:37
A road/street connecting two junctions.
Definition: MSEdge.h:76
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:48
std::string routeid
The vehicle&#39;s route id.
Representation of a vehicle.
Definition: SUMOVehicle.h:61
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:337
bool myEagerInsertionCheck
Whether an edge on which a vehicle could not depart should be ignored in the same step...
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:284
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)
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:83
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:375
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