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 /****************************************************************************/
10 /// @file    MSInsertionControl.cpp
11 /// @author  Christian Roessel
12 /// @author  Daniel Krajzewicz
13 /// @author  Axel Wegener
14 /// @author  Michael Behrisch
15 /// @author  Jakob Erdmann
16 /// @date    Mon, 12 Mar 2001
17 /// @version $Id$
18 ///
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>
32 #include <utils/router/IntermodalRouter.h>
33 #include <microsim/devices/MSDevice_Routing.h>
34 #include <microsim/devices/MSRoutingEngine.h>
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 // ===========================================================================
MSInsertionControl(MSVehicleControl & vc,SUMOTime maxDepartDelay,bool eagerInsertionCheck,int maxVehicleNumber,SUMOTime randomDepartOffset)48 MSInsertionControl::MSInsertionControl(MSVehicleControl& vc,
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;
59     RandHelper::initRandGlobal(&myFlowRNG);
60 }
61 
62 
~MSInsertionControl()63 MSInsertionControl::~MSInsertionControl() {
64     for (std::vector<Flow>::iterator i = myFlows.begin(); i != myFlows.end(); ++i) {
65         delete (i->pars);
66     }
67 }
68 
69 
70 void
add(SUMOVehicle * veh)71 MSInsertionControl::add(SUMOVehicle* veh) {
72     myAllVeh.add(veh);
73 }
74 
75 
76 bool
addFlow(SUMOVehicleParameter * const pars,int index)77 MSInsertionControl::addFlow(SUMOVehicleParameter* const pars, int index) {
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)) {
90                     pars->parametersSet |= 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
emitVehicles(SUMOTime time)110 MSInsertionControl::emitVehicles(SUMOTime time) {
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
121     MSVehicleContainer::VehicleVector refusedEmits;
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
tryInsert(SUMOTime time,SUMOVehicle * veh,MSVehicleContainer::VehicleVector & refusedEmits)139 MSInsertionControl::tryInsert(SUMOTime time, SUMOVehicle* veh,
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
checkCandidates(SUMOTime time,const bool preCheck)171 MSInsertionControl::checkCandidates(SUMOTime time, const bool preCheck) {
172     while (myAllVeh.anyWaitingBefore(time + DELTA_T)) {
173         const MSVehicleContainer::VehicleVector& top = myAllVeh.top();
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
determineCandidates(SUMOTime time)196 MSInsertionControl::determineCandidates(SUMOTime time) {
197     MSVehicleControl& vehControl = MSNet::getInstance()->getVehicleControl();
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
208                     && RandHelper::rand(&myFlowRNG) < (pars->repetitionProbability * TS))
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 :
229                                             (SUMOTime)(pars->depart + pars->repetitionsDone * pars->repetitionOffset) + computeRandomDepartOffset();
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
240                 if (MSGlobals::gStateLoaded) {
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);
249             MSRoute::checkDist(pars->routeid);
250             delete pars;
251         } else {
252             ++i;
253         }
254     }
255     checkCandidates(time, MSRoutingEngine::isEnabled());
256 }
257 
258 
259 int
getWaitingVehicleNo() const260 MSInsertionControl::getWaitingVehicleNo() const {
261     return (int)myPendingEmits.size();
262 }
263 
264 
265 int
getPendingFlowCount() const266 MSInsertionControl::getPendingFlowCount() const {
267     return (int)myFlows.size();
268 }
269 
270 
271 void
descheduleDeparture(const SUMOVehicle * veh)272 MSInsertionControl::descheduleDeparture(const SUMOVehicle* veh) {
273     myAbortedEmits.insert(veh);
274 }
275 
276 
277 void
alreadyDeparted(SUMOVehicle * veh)278 MSInsertionControl::alreadyDeparted(SUMOVehicle* veh) {
279     myPendingEmits.erase(std::remove(myPendingEmits.begin(), myPendingEmits.end(), veh), myPendingEmits.end());
280     myAllVeh.remove(veh);
281 }
282 
283 
284 void
clearPendingVehicles(const std::string & route)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
getPendingEmits(const MSLane * lane)300 MSInsertionControl::getPendingEmits(const MSLane* lane) {
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         }
318         myPendingEmitsUpdateTime = MSNet::getInstance()->getCurrentTimeStep();
319     }
320     return myPendingEmitsForLane[lane];
321 }
322 
323 
324 void
adaptIntermodalRouter(MSNet::MSIntermodalRouter & router) const325 MSInsertionControl::adaptIntermodalRouter(MSNet::MSIntermodalRouter& router) const {
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
saveState(OutputDevice & out)337 MSInsertionControl::saveState(OutputDevice& out) {
338     // save flow states
339     for (const Flow& flow : myFlows) {
340         out.openTag(SUMO_TAG_FLOWSTATE);
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
computeRandomDepartOffset() const352 MSInsertionControl::computeRandomDepartOffset() const {
353     if (myMaxRandomDepartOffset > 0) {
354         // round to the closest usable simulation step
355         return DELTA_T * int((RandHelper::rand((int)myMaxRandomDepartOffset, MSRouteHandler::getParsingRNG()) + 0.5 * DELTA_T) / DELTA_T);
356     } else {
357         return 0;
358     }
359 }
360 
361 
362 
363 /****************************************************************************/
364