Line data Source code
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 : /****************************************************************************/
14 : /// @file MSInsertionControl.cpp
15 : /// @author Christian Roessel
16 : /// @author Daniel Krajzewicz
17 : /// @author Axel Wegener
18 : /// @author Michael Behrisch
19 : /// @author Jakob Erdmann
20 : /// @author Mirko Barthauer
21 : /// @date Mon, 12 Mar 2001
22 : ///
23 : // Inserts vehicles into the network when their departure time is reached
24 : /****************************************************************************/
25 : #include <config.h>
26 :
27 : #include <iostream>
28 : #include <algorithm>
29 : #include <cassert>
30 : #include <iterator>
31 : #include <utils/router/IntermodalRouter.h>
32 : #include <microsim/devices/MSDevice_Routing.h>
33 : #include <microsim/devices/MSRoutingEngine.h>
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 : // ===========================================================================
47 42995 : MSInsertionControl::MSInsertionControl(MSVehicleControl& vc,
48 : SUMOTime maxDepartDelay,
49 : bool eagerInsertionCheck,
50 : int maxVehicleNumber,
51 42995 : SUMOTime randomDepartOffset) :
52 42995 : myVehicleControl(vc),
53 42995 : myMaxDepartDelay(maxDepartDelay),
54 42995 : myEagerInsertionCheck(eagerInsertionCheck),
55 42995 : myMaxVehicleNumber(maxVehicleNumber),
56 42995 : myPendingEmitsUpdateTime(SUMOTime_MIN),
57 85990 : myFlowRNG("flow") {
58 42995 : myMaxRandomDepartOffset = randomDepartOffset;
59 42995 : RandHelper::initRandGlobal(&myFlowRNG);
60 42995 : }
61 :
62 :
63 40024 : MSInsertionControl::~MSInsertionControl() {
64 42314 : for (const Flow& f : myFlows) {
65 2290 : delete (f.pars);
66 : }
67 80048 : }
68 :
69 :
70 : void
71 4957979 : MSInsertionControl::add(SUMOVehicle* veh) {
72 4957979 : myAllVeh.add(veh);
73 4957979 : }
74 :
75 :
76 : bool
77 18810 : MSInsertionControl::addFlow(SUMOVehicleParameter* const pars, int index) {
78 18810 : if (myFlowIDs.count(pars->id) > 0) {
79 34 : return false;
80 : }
81 : const bool loadingFromState = index >= 0;
82 18776 : Flow flow{pars, loadingFromState ? index : 0, initScale(pars->vtypeid)};
83 18776 : if (!loadingFromState && pars->repetitionProbability < 0 && pars->repetitionOffset < 0) {
84 : // init poisson flow (but only the timing)
85 422 : flow.pars->incrementFlow(flow.scale, &myFlowRNG);
86 422 : flow.pars->repetitionsDone--;
87 : }
88 18776 : myFlows.emplace_back(flow);
89 18776 : myFlowIDs.insert(std::make_pair(pars->id, flow.index));
90 18776 : return true;
91 : }
92 :
93 :
94 : double
95 18776 : MSInsertionControl::initScale(const std::string vtypeid) {
96 18776 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
97 18776 : if (vc.hasVTypeDistribution(vtypeid)) {
98 : double result = -1;
99 796 : const RandomDistributor<MSVehicleType*>* dist = vc.getVTypeDistribution(vtypeid);
100 2506 : for (const MSVehicleType* t : dist->getVals()) {
101 1710 : if (result == -1) {
102 796 : result = t->getParameter().scale;
103 914 : } else if (result != t->getParameter().scale) {
104 : // unequal scales in distribution
105 : return -1;
106 : }
107 : }
108 796 : return result;
109 : } else {
110 : // rng is not used since vtypeid is not a distribution
111 17980 : return vc.getVType(vtypeid, nullptr, true)->getParameter().scale;
112 : }
113 : }
114 :
115 :
116 : void
117 5 : MSInsertionControl::updateScale(const std::string vtypeid) {
118 5 : for (Flow& f : myFlows) {
119 0 : if (f.pars->vtypeid == vtypeid) {
120 0 : f.scale = initScale(vtypeid);
121 : }
122 : }
123 5 : }
124 :
125 :
126 : int
127 91771781 : MSInsertionControl::emitVehicles(SUMOTime time) {
128 : // check whether any vehicles shall be emitted within this time step
129 : const bool havePreChecked = MSRoutingEngine::isEnabled();
130 91771781 : if (myPendingEmits.empty() || (havePreChecked && myEmitCandidates.empty())) {
131 : return 0;
132 : }
133 : int numEmitted = 0;
134 : // we use buffering for the refused emits to save time
135 : // for this, we have two lists; one contains previously refused emits, the second
136 : // will be used to append those vehicles that will not be able to depart in this
137 : // time step
138 : MSVehicleContainer::VehicleVector refusedEmits;
139 :
140 : // go through the list of previously refused vehicles, first
141 : MSVehicleContainer::VehicleVector::const_iterator veh;
142 2075364382 : for (veh = myPendingEmits.begin(); veh != myPendingEmits.end(); veh++) {
143 2067514980 : if (havePreChecked && (myEmitCandidates.count(*veh) == 0)) {
144 5683619 : refusedEmits.push_back(*veh);
145 : } else {
146 2061831361 : numEmitted += tryInsert(time, *veh, refusedEmits);
147 : }
148 : }
149 : myEmitCandidates.clear();
150 7849402 : myPendingEmits = refusedEmits;
151 : return numEmitted;
152 7849546 : }
153 :
154 :
155 : int
156 2061831361 : MSInsertionControl::tryInsert(SUMOTime time, SUMOVehicle* veh,
157 : MSVehicleContainer::VehicleVector& refusedEmits) {
158 : assert(veh->getParameter().depart <= time);
159 2061831361 : const MSEdge& edge = *veh->getEdge();
160 2061831361 : if (veh->isOnRoad()) {
161 : return 1;
162 : }
163 528048 : if ((myMaxVehicleNumber < 0 || (int)MSNet::getInstance()->getVehicleControl().getRunningVehicleNo() < myMaxVehicleNumber)
164 2061842126 : && edge.insertVehicle(*veh, time, false, myEagerInsertionCheck || veh->getParameter().departProcedure == DepartDefinition::SPLIT)) {
165 : // Successful insertion
166 : return 1;
167 : }
168 2058321770 : if (myMaxDepartDelay >= 0 && time - veh->getParameter().depart > myMaxDepartDelay) {
169 : // remove vehicles waiting too long for departure
170 731571 : myVehicleControl.deleteVehicle(veh, true);
171 2057590199 : } else if (edge.isVaporizing()) {
172 : // remove vehicles if the edge shall be empty
173 13002 : myVehicleControl.deleteVehicle(veh, true);
174 2057577197 : } else if (myAbortedEmits.count(veh) > 0) {
175 : // remove vehicles which shall not be inserted for some reason
176 498 : myAbortedEmits.erase(veh);
177 498 : myVehicleControl.deleteVehicle(veh, true);
178 2057576699 : } else if ((veh->getRouteValidity(false) & (
179 : MSBaseVehicle::ROUTE_START_INVALID_LANE
180 : | MSBaseVehicle::ROUTE_START_INVALID_PERMISSIONS)) != 0) {
181 46 : myVehicleControl.deleteVehicle(veh, true);
182 : } else {
183 : // let the vehicle wait one step, we'll retry then
184 2057576653 : refusedEmits.push_back(veh);
185 : }
186 : edge.setLastFailedInsertionTime(time);
187 2058321770 : return 0;
188 : }
189 :
190 :
191 : void
192 91771940 : MSInsertionControl::checkCandidates(SUMOTime time, const bool preCheck) {
193 95178705 : while (myAllVeh.anyWaitingBefore(time)) {
194 3406765 : const MSVehicleContainer::VehicleVector& top = myAllVeh.top();
195 3406765 : copy(top.begin(), top.end(), back_inserter(myPendingEmits));
196 3406765 : myAllVeh.pop();
197 : }
198 91771940 : if (preCheck) {
199 : MSVehicleContainer::VehicleVector::const_iterator veh;
200 729267360 : for (veh = myPendingEmits.begin(); veh != myPendingEmits.end(); veh++) {
201 718866030 : SUMOVehicle* const v = *veh;
202 718866030 : const MSEdge* const edge = v->getEdge();
203 718866030 : if (edge->insertVehicle(*v, time, true, myEagerInsertionCheck)) {
204 : myEmitCandidates.insert(v);
205 : } else {
206 38466863 : MSDevice_Routing* dev = static_cast<MSDevice_Routing*>(v->getDevice(typeid(MSDevice_Routing)));
207 : if (dev != nullptr) {
208 : dev->skipRouting(time);
209 : }
210 : }
211 : }
212 : }
213 91771902 : }
214 :
215 :
216 : void
217 91771947 : MSInsertionControl::determineCandidates(SUMOTime time) {
218 91771947 : MSVehicleControl& vehControl = MSNet::getInstance()->getVehicleControl();
219 : // for equidistant vehicles, up-scaling is done via repetitionOffset
220 122017725 : for (std::vector<Flow>::iterator i = myFlows.begin(); i != myFlows.end();) {
221 : MSVehicleType* vtype = nullptr;
222 30245785 : SUMOVehicleParameter* pars = i->pars;
223 30245785 : double typeScale = i->scale;
224 30245785 : if (typeScale < 0) {
225 : // must sample from distribution to determine scale value
226 0 : vtype = vehControl.getVType(pars->vtypeid, MSRouteHandler::getParsingRNG());
227 0 : typeScale = vtype->getParameter().scale;
228 : }
229 30245785 : double scale = vehControl.getScale() * typeScale;
230 30245785 : bool tryEmitByProb = pars->repetitionProbability > 0;
231 34852289 : while (scale > 0 && ((pars->repetitionProbability < 0
232 25659956 : && pars->repetitionsDone < pars->repetitionNumber * scale
233 25647254 : && pars->depart + pars->repetitionTotalOffset <= time)
234 30736682 : || (tryEmitByProb
235 8701429 : && pars->depart <= time
236 8693518 : && pars->repetitionEnd > time
237 : // only call rand if all other conditions are met
238 8690152 : && RandHelper::rand(&myFlowRNG) < (pars->repetitionProbability * TS))
239 : )) {
240 : tryEmitByProb = false; // only emit one per step
241 4606511 : SUMOVehicleParameter* newPars = new SUMOVehicleParameter(*pars);
242 9213022 : newPars->id = pars->id + "." + toString(i->index);
243 4606511 : newPars->depart = pars->repetitionProbability > 0 ? time : pars->depart + pars->repetitionTotalOffset + computeRandomDepartOffset();
244 4606511 : pars->incrementFlow(scale, &myFlowRNG);
245 4606511 : myFlowIDs[pars->id] = i->index;
246 : //std::cout << SIMTIME << " flow=" << pars->id << " done=" << pars->repetitionsDone << " totalOffset=" << STEPS2TIME(pars->repetitionTotalOffset) << "\n";
247 : // try to build the vehicle
248 4606511 : if (vehControl.getVehicle(newPars->id) == nullptr) {
249 4606511 : ConstMSRoutePtr const route = MSRoute::dictionary(pars->routeid);
250 4606511 : if (vtype == nullptr) {
251 4606511 : vtype = vehControl.getVType(pars->vtypeid, MSRouteHandler::getParsingRNG());
252 : }
253 4606511 : SUMOVehicle* const vehicle = vehControl.buildVehicle(newPars, route, vtype, !MSGlobals::gCheckRoutes);
254 : // for equidistant vehicles, all scaling is done via repetitionOffset (to avoid artefacts, #11441)
255 : // for probabilistic vehicles, we use the quota
256 4606504 : int quota = pars->repetitionProbability < 0 ? 1 : vehControl.getQuota(scale);
257 490904 : if (quota > 0) {
258 4582738 : vehControl.addVehicle(newPars->id, vehicle);
259 4582738 : if (pars->departProcedure == DepartDefinition::GIVEN || pars->departProcedure == DepartDefinition::BEGIN) {
260 4582714 : add(vehicle);
261 : }
262 4582738 : i->index++;
263 4639317 : while (--quota > 0) {
264 56579 : SUMOVehicleParameter* const quotaPars = new SUMOVehicleParameter(*pars);
265 113158 : quotaPars->id = pars->id + "." + toString(i->index);
266 56579 : quotaPars->depart = pars->repetitionProbability > 0 ? time :
267 0 : pars->depart + pars->repetitionsDone * pars->repetitionTotalOffset + computeRandomDepartOffset();
268 56586 : SUMOVehicle* const quotaVehicle = vehControl.buildVehicle(quotaPars, route, vtype, !MSGlobals::gCheckRoutes);
269 56579 : vehControl.addVehicle(quotaPars->id, quotaVehicle);
270 56579 : if (pars->departProcedure == DepartDefinition::GIVEN || pars->departProcedure == DepartDefinition::BEGIN) {
271 56579 : add(quotaVehicle);
272 : }
273 56579 : pars->repetitionsDone++;
274 56579 : i->index++;
275 : }
276 : } else {
277 23766 : vehControl.deleteVehicle(vehicle, true);
278 : }
279 : } else {
280 0 : if (MSGlobals::gStateLoaded) {
281 : /// @note probably obsolete since flows save their state
282 : break;
283 : }
284 0 : throw ProcessError(TLF("Another vehicle with the id '%' exists.", newPars->id));
285 : }
286 : vtype = nullptr;
287 : }
288 30245778 : if (time >= pars->repetitionEnd ||
289 30241216 : (pars->repetitionNumber != std::numeric_limits<int>::max()
290 19578185 : && pars->repetitionsDone >= (int)(pars->repetitionNumber * scale + 0.5))) {
291 16475 : i = myFlows.erase(i);
292 16475 : MSRoute::checkDist(pars->routeid);
293 16475 : delete pars;
294 : } else {
295 : ++i;
296 : }
297 : }
298 91771940 : checkCandidates(time, MSRoutingEngine::isEnabled());
299 91771902 : }
300 :
301 :
302 : int
303 6359339 : MSInsertionControl::getWaitingVehicleNo() const {
304 6359339 : return (int)myPendingEmits.size();
305 : }
306 :
307 :
308 : int
309 11813459 : MSInsertionControl::getPendingFlowCount() const {
310 11813459 : return (int)myFlows.size();
311 : }
312 :
313 :
314 : void
315 542 : MSInsertionControl::descheduleDeparture(const SUMOVehicle* veh) {
316 542 : myAbortedEmits.insert(veh);
317 542 : }
318 :
319 : void
320 15085 : MSInsertionControl::retractDescheduleDeparture(const SUMOVehicle* veh) {
321 15085 : myAbortedEmits.erase(veh);
322 15085 : }
323 :
324 :
325 : void
326 2292 : MSInsertionControl::alreadyDeparted(SUMOVehicle* veh) {
327 2292 : myPendingEmits.erase(std::remove(myPendingEmits.begin(), myPendingEmits.end(), veh), myPendingEmits.end());
328 2292 : myAllVeh.remove(veh);
329 2292 : }
330 :
331 :
332 : void
333 6 : MSInsertionControl::clearPendingVehicles(const std::string& route) {
334 : //clear out the refused vehicle list, deleting the vehicles entirely
335 : MSVehicleContainer::VehicleVector::iterator veh;
336 12 : for (veh = myPendingEmits.begin(); veh != myPendingEmits.end();) {
337 6 : if ((*veh)->getRoute().getID() == route || route == "") {
338 6 : myVehicleControl.deleteVehicle(*veh, true);
339 6 : veh = myPendingEmits.erase(veh);
340 : } else {
341 : ++veh;
342 : }
343 : }
344 6 : }
345 :
346 :
347 : int
348 0 : MSInsertionControl::getPendingEmits(const MSLane* lane) {
349 0 : if (MSNet::getInstance()->getCurrentTimeStep() != myPendingEmitsUpdateTime) {
350 : // updated pending emits (only once per time step)
351 : myPendingEmitsForLane.clear();
352 0 : for (const SUMOVehicle* const veh : myPendingEmits) {
353 0 : const MSLane* const vlane = veh->getLane();
354 0 : if (vlane != nullptr) {
355 0 : myPendingEmitsForLane[vlane]++;
356 : } else {
357 : // no (tentative) departLane was set, increase count for all
358 : // lanes of the depart edge
359 0 : for (const MSLane* const l : veh->getEdge()->getLanes()) {
360 0 : myPendingEmitsForLane[l]++;
361 : }
362 : }
363 : }
364 0 : myPendingEmitsUpdateTime = MSNet::getInstance()->getCurrentTimeStep();
365 : }
366 0 : return myPendingEmitsForLane[lane];
367 : }
368 :
369 :
370 : void
371 4247 : MSInsertionControl::adaptIntermodalRouter(MSTransportableRouter& router) const {
372 : // fill the public transport router with pre-parsed public transport lines
373 6132 : for (const Flow& f : myFlows) {
374 1885 : if (f.pars->line != "") {
375 511 : ConstMSRoutePtr const route = MSRoute::dictionary(f.pars->routeid);
376 511 : router.getNetwork()->addSchedule(*f.pars, route == nullptr ? nullptr : &route->getStops());
377 : }
378 : }
379 4247 : }
380 :
381 :
382 : void
383 425 : MSInsertionControl::saveState(OutputDevice& out) {
384 : // save flow states
385 499 : for (const Flow& flow : myFlows) {
386 74 : flow.pars->write(out, OptionsCont::getOptions(), SUMO_TAG_FLOWSTATE,
387 74 : flow.pars->vtypeid == DEFAULT_VTYPE_ID ? "" : flow.pars->vtypeid);
388 74 : if (flow.pars->repetitionEnd == SUMOTime_MAX) {
389 0 : out.writeAttr(SUMO_ATTR_NUMBER, flow.pars->repetitionNumber);
390 : }
391 74 : if (flow.pars->repetitionProbability > 0) {
392 14 : out.writeAttr(SUMO_ATTR_PROB, flow.pars->repetitionProbability);
393 60 : } else if (flow.pars->poissonRate > 0) {
394 1 : out.writeAttr(SUMO_ATTR_PERIOD, "exp(" + toString(flow.pars->poissonRate) + ")");
395 2 : out.writeAttr(SUMO_ATTR_NEXT, STEPS2TIME(flow.pars->repetitionTotalOffset));
396 : } else {
397 59 : out.writeAttr(SUMO_ATTR_PERIOD, STEPS2TIME(flow.pars->repetitionOffset));
398 118 : out.writeAttr(SUMO_ATTR_NEXT, STEPS2TIME(flow.pars->repetitionTotalOffset));
399 : }
400 74 : if (flow.pars->repetitionEnd != SUMOTime_MAX) {
401 148 : out.writeAttr(SUMO_ATTR_END, STEPS2TIME(flow.pars->repetitionEnd));
402 : };
403 74 : out.writeAttr(SUMO_ATTR_ROUTE, flow.pars->routeid);
404 74 : out.writeAttr(SUMO_ATTR_DONE, flow.pars->repetitionsDone);
405 74 : out.writeAttr(SUMO_ATTR_INDEX, flow.index);
406 74 : if (flow.pars->wasSet(VEHPARS_FORCE_REROUTE)) {
407 38 : out.writeAttr(SUMO_ATTR_REROUTE, true);
408 : }
409 148 : out.closeTag();
410 : }
411 425 : }
412 :
413 :
414 : void
415 177 : MSInsertionControl::clearState() {
416 177 : for (const Flow& f : myFlows) {
417 0 : delete (f.pars);
418 : }
419 : myFlows.clear();
420 : myFlowIDs.clear();
421 177 : myAllVeh.clearState();
422 : myPendingEmits.clear();
423 : myEmitCandidates.clear();
424 177 : myAbortedEmits.clear();
425 : // myPendingEmitsForLane must not be cleared since it updates itself on the next call
426 177 : }
427 :
428 :
429 : SUMOTime
430 4911694 : MSInsertionControl::computeRandomDepartOffset() const {
431 4911694 : if (myMaxRandomDepartOffset > 0) {
432 : // round to the closest usable simulation step
433 90 : return DELTA_T * ((RandHelper::rand(myMaxRandomDepartOffset, MSRouteHandler::getParsingRNG()) + DELTA_T / 2) / DELTA_T);
434 : }
435 : return 0;
436 : }
437 :
438 : const SUMOVehicleParameter*
439 32 : MSInsertionControl::getFlowPars(const std::string& id) const {
440 : if (hasFlow(id)) {
441 32 : for (const Flow& f : myFlows) {
442 32 : if (f.pars->id == id) {
443 : return f.pars;
444 : }
445 : }
446 : }
447 : return nullptr;
448 : }
449 :
450 : SUMOVehicle*
451 568 : MSInsertionControl::getLastFlowVehicle(const std::string& id) const {
452 : const auto it = myFlowIDs.find(id);
453 568 : if (it != myFlowIDs.end()) {
454 1136 : const std::string vehID = id + "." + toString(it->second);
455 568 : return MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
456 : }
457 : return nullptr;
458 : }
459 :
460 : /****************************************************************************/
|