Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2026 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 42946 : MSInsertionControl::MSInsertionControl(MSVehicleControl& vc,
48 : SUMOTime maxDepartDelay,
49 : bool eagerInsertionCheck,
50 : int maxVehicleNumber,
51 42946 : SUMOTime randomDepartOffset) :
52 42946 : myVehicleControl(vc),
53 42946 : myMaxDepartDelay(maxDepartDelay),
54 42946 : myEagerInsertionCheck(eagerInsertionCheck),
55 42946 : myMaxVehicleNumber(maxVehicleNumber),
56 42946 : myPendingEmitsUpdateTime(SUMOTime_MIN),
57 85892 : myFlowRNG("flow") {
58 42946 : myMaxRandomDepartOffset = randomDepartOffset;
59 42946 : RandHelper::initRandGlobal(&myFlowRNG);
60 42946 : }
61 :
62 :
63 42328 : MSInsertionControl::~MSInsertionControl() {
64 45157 : for (const Flow& f : myFlows) {
65 2829 : delete (f.pars);
66 : }
67 84656 : }
68 :
69 :
70 : void
71 5316852 : MSInsertionControl::add(SUMOVehicle* veh) {
72 5316852 : myAllVeh.add(veh);
73 5316852 : }
74 :
75 :
76 : bool
77 19791 : MSInsertionControl::addFlow(SUMOVehicleParameter* const pars, int index) {
78 19791 : if (myFlowIDs.count(pars->id) > 0) {
79 39 : return false;
80 : }
81 : const bool loadingFromState = index >= 0;
82 19752 : Flow flow{pars, loadingFromState ? index : 0, initScale(pars->vtypeid)};
83 19752 : if (!loadingFromState && pars->repetitionProbability < 0 && pars->repetitionOffset < 0) {
84 : // init poisson flow (but only the timing)
85 781 : flow.pars->incrementFlow(flow.scale, &myFlowRNG);
86 781 : flow.pars->repetitionsDone--;
87 : }
88 19752 : myFlows.emplace_back(flow);
89 19752 : myFlowIDs.insert(std::make_pair(pars->id, flow.index));
90 19752 : return true;
91 : }
92 :
93 :
94 : double
95 19752 : MSInsertionControl::initScale(const std::string vtypeid) {
96 19752 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
97 19752 : if (vc.hasVTypeDistribution(vtypeid)) {
98 : double result = -1;
99 846 : const RandomDistributor<MSVehicleType*>* dist = vc.getVTypeDistribution(vtypeid);
100 2672 : for (const MSVehicleType* t : dist->getVals()) {
101 1826 : if (result == -1) {
102 846 : result = t->getParameter().scale;
103 980 : } else if (result != t->getParameter().scale) {
104 : // unequal scales in distribution
105 : return -1;
106 : }
107 : }
108 846 : return result;
109 : } else {
110 : // rng is not used since vtypeid is not a distribution
111 18906 : 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 138409372 : MSInsertionControl::emitVehicles(SUMOTime time) {
128 : // check whether any vehicles shall be emitted within this time step
129 : const bool havePreChecked = MSRoutingEngine::isEnabled();
130 138409372 : 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 20604492 : MSNet::getInstance()->lockPendingEmits();
142 : MSVehicleContainer::VehicleVector::const_iterator veh;
143 2158213928 : for (veh = myPendingEmits.begin(); veh != myPendingEmits.end(); veh++) {
144 2137609582 : if (havePreChecked && (myEmitCandidates.count(*veh) == 0)) {
145 4129741 : refusedEmits.push_back(*veh);
146 : } else {
147 2133479841 : numEmitted += tryInsert(time, *veh, refusedEmits);
148 : }
149 : }
150 : myEmitCandidates.clear();
151 20604346 : myPendingEmits = refusedEmits;
152 20604346 : MSNet::getInstance()->unlockPendingEmits();
153 : return numEmitted;
154 20604492 : }
155 :
156 :
157 : int
158 2133479841 : MSInsertionControl::tryInsert(SUMOTime time, SUMOVehicle* veh,
159 : MSVehicleContainer::VehicleVector& refusedEmits) {
160 : assert(veh->getParameter().depart <= time);
161 2133479841 : const MSEdge& edge = *veh->getEdge();
162 2133479841 : if (veh->isOnRoad()) {
163 : return 1;
164 : }
165 475184 : if ((myMaxVehicleNumber < 0 || (int)MSNet::getInstance()->getVehicleControl().getRunningVehicleNo() < myMaxVehicleNumber)
166 2133490964 : && edge.insertVehicle(*veh, time, false, myEagerInsertionCheck || veh->getParameter().departProcedure == DepartDefinition::SPLIT)) {
167 : // Successful insertion
168 : return 1;
169 : }
170 2129185529 : if (myMaxDepartDelay >= 0 && time - veh->getParameter().depart > myMaxDepartDelay) {
171 : // remove vehicles waiting too long for departure
172 2036 : myVehicleControl.deleteVehicle(veh, true);
173 2129183493 : } else if (edge.isVaporizing()) {
174 : // remove vehicles if the edge shall be empty
175 12818 : myVehicleControl.deleteVehicle(veh, true);
176 2129170675 : } else if (myAbortedEmits.count(veh) > 0) {
177 : // remove vehicles which shall not be inserted for some reason
178 458 : myAbortedEmits.erase(veh);
179 458 : myVehicleControl.deleteVehicle(veh, true);
180 2129170217 : } else if ((veh->getRouteValidity(false) & (
181 : MSBaseVehicle::ROUTE_START_INVALID_LANE
182 : | MSBaseVehicle::ROUTE_START_INVALID_PERMISSIONS)) != 0) {
183 46 : myVehicleControl.deleteVehicle(veh, true);
184 : } else {
185 : // let the vehicle wait one step, we'll retry then
186 2129170171 : refusedEmits.push_back(veh);
187 : }
188 : edge.setLastFailedInsertionTime(time);
189 2129185529 : return 0;
190 : }
191 :
192 :
193 : void
194 138409529 : MSInsertionControl::checkCandidates(SUMOTime time, const bool preCheck) {
195 138409529 : if (myMaxDepartDelay >= 0) {
196 40178060 : for (auto it = myPendingEmits.begin(); it != myPendingEmits.end();) {
197 36635400 : SUMOVehicle* veh = *it;
198 36635400 : if (time - veh->getParameter().depart > myMaxDepartDelay) {
199 : // remove vehicles waiting too long for departure
200 845867 : myVehicleControl.deleteVehicle(veh, true);
201 845867 : it = myPendingEmits.erase(it);
202 : } else {
203 : it++;
204 : }
205 : }
206 : }
207 142234217 : while (myAllVeh.anyWaitingBefore(time)) {
208 3824688 : const MSVehicleContainer::VehicleVector& top = myAllVeh.top();
209 3824688 : copy(top.begin(), top.end(), back_inserter(myPendingEmits));
210 3824688 : myAllVeh.pop();
211 : }
212 138409529 : if (preCheck) {
213 : MSVehicleContainer::VehicleVector::const_iterator veh;
214 778722670 : for (veh = myPendingEmits.begin(); veh != myPendingEmits.end(); veh++) {
215 692592820 : SUMOVehicle* const v = *veh;
216 692592820 : const MSEdge* const edge = v->getEdge();
217 692592820 : if (edge->insertVehicle(*v, time, true, myEagerInsertionCheck)) {
218 : myEmitCandidates.insert(v);
219 : } else {
220 86503056 : MSDevice_Routing* dev = static_cast<MSDevice_Routing*>(v->getDevice(typeid(MSDevice_Routing)));
221 : if (dev != nullptr) {
222 : dev->skipRouting(time);
223 : }
224 : }
225 : }
226 : }
227 138409491 : }
228 :
229 :
230 : void
231 138409538 : MSInsertionControl::determineCandidates(SUMOTime time) {
232 138409538 : MSVehicleControl& vehControl = MSNet::getInstance()->getVehicleControl();
233 : // for equidistant vehicles, up-scaling is done via repetitionOffset
234 172717992 : for (std::vector<Flow>::iterator i = myFlows.begin(); i != myFlows.end();) {
235 : MSVehicleType* vtype = nullptr;
236 34308463 : SUMOVehicleParameter* const pars = i->pars;
237 34308463 : double typeScale = i->scale;
238 34308463 : if (typeScale < 0) {
239 : // must sample from distribution to determine scale value
240 0 : vtype = vehControl.getVType(pars->vtypeid, MSRouteHandler::getParsingRNG());
241 0 : typeScale = vtype->getParameter().scale;
242 : }
243 34308463 : const double scale = vehControl.getScale() * typeScale;
244 34308463 : const long long int scaledRepetitions = pars->repetitionNumber == std::numeric_limits<long long int>::max() ? std::numeric_limits<long long int>::max() :
245 22697631 : (long long int)((double)pars->repetitionNumber * scale + 0.5);
246 34308463 : bool tryEmitByProb = pars->repetitionProbability > 0;
247 39255419 : while (scale > 0 && ((pars->repetitionProbability < 0
248 29598768 : && pars->repetitionsDone < scaledRepetitions
249 29586232 : && pars->depart + pars->repetitionTotalOffset <= time)
250 34867114 : || (tryEmitByProb
251 9097991 : && pars->depart <= time
252 9078071 : && pars->repetitionEnd > time
253 : // only call rand if all other conditions are met
254 9074354 : && RandHelper::rand(&myFlowRNG) < (pars->repetitionProbability * TS))
255 : )) {
256 : tryEmitByProb = false; // only emit one per step
257 4946965 : SUMOVehicleParameter* const newPars = new SUMOVehicleParameter(*pars);
258 9893930 : newPars->id = pars->id + "." + toString(i->index);
259 4946965 : newPars->depart = pars->repetitionProbability > 0 ? time : pars->depart + pars->repetitionTotalOffset + computeRandomDepartOffset();
260 4946965 : pars->incrementFlow(scale, &myFlowRNG);
261 4946965 : myFlowIDs[pars->id] = i->index;
262 : //std::cout << SIMTIME << " flow=" << pars->id << " done=" << pars->repetitionsDone << " totalOffset=" << STEPS2TIME(pars->repetitionTotalOffset) << "\n";
263 : // try to build the vehicle
264 4946965 : if (vehControl.getVehicle(newPars->id) == nullptr) {
265 4946965 : ConstMSRoutePtr const route = MSRoute::dictionary(pars->routeid);
266 4946965 : if (vtype == nullptr) {
267 4946965 : vtype = vehControl.getVType(pars->vtypeid, MSRouteHandler::getParsingRNG());
268 : }
269 4946965 : SUMOVehicle* const vehicle = vehControl.buildVehicle(newPars, route, vtype, !MSGlobals::gCheckRoutes);
270 : // for equidistant vehicles, all scaling is done via repetitionOffset (to avoid artefacts, #11441)
271 : // for probabilistic vehicles, we use the quota
272 4946956 : int quota = pars->repetitionProbability < 0 ? 1 : vehControl.getQuota(scale);
273 558660 : if (quota > 0) {
274 4923190 : vehControl.addVehicle(newPars->id, vehicle);
275 4923190 : if (pars->departProcedure == DepartDefinition::GIVEN || pars->departProcedure == DepartDefinition::BEGIN) {
276 4923166 : add(vehicle);
277 : }
278 4923190 : i->index++;
279 4979769 : while (--quota > 0) {
280 56579 : SUMOVehicleParameter* const quotaPars = new SUMOVehicleParameter(*pars);
281 113158 : quotaPars->id = pars->id + "." + toString(i->index);
282 56579 : quotaPars->depart = pars->repetitionProbability > 0 ? time :
283 0 : pars->depart + pars->repetitionsDone * pars->repetitionTotalOffset + computeRandomDepartOffset();
284 56588 : SUMOVehicle* const quotaVehicle = vehControl.buildVehicle(quotaPars, route, vtype, !MSGlobals::gCheckRoutes);
285 56579 : vehControl.addVehicle(quotaPars->id, quotaVehicle);
286 56579 : if (pars->departProcedure == DepartDefinition::GIVEN || pars->departProcedure == DepartDefinition::BEGIN) {
287 56579 : add(quotaVehicle);
288 : }
289 56579 : pars->repetitionsDone++;
290 56579 : i->index++;
291 : }
292 : } else {
293 23766 : vehControl.deleteVehicle(vehicle, true);
294 : }
295 : } else {
296 0 : if (MSGlobals::gStateLoaded) {
297 : /// @note probably obsolete since flows save their state
298 : break;
299 : }
300 0 : throw ProcessError(TLF("Another vehicle with the id '%' exists.", newPars->id));
301 : }
302 : vtype = nullptr;
303 : }
304 34308454 : if (time >= pars->repetitionEnd || pars->repetitionsDone >= scaledRepetitions) {
305 16902 : i = myFlows.erase(i);
306 16902 : MSRoute::checkDist(pars->routeid);
307 16902 : delete pars;
308 : } else {
309 : ++i;
310 : }
311 : }
312 138409529 : checkCandidates(time, MSRoutingEngine::isEnabled());
313 138409491 : }
314 :
315 :
316 : int
317 13686876 : MSInsertionControl::getWaitingVehicleNo() const {
318 13686876 : return (int)myPendingEmits.size();
319 : }
320 :
321 :
322 : int
323 86810179 : MSInsertionControl::getPendingFlowCount() const {
324 86810179 : return (int)myFlows.size();
325 : }
326 :
327 :
328 : void
329 471 : MSInsertionControl::descheduleDeparture(const SUMOVehicle* veh) {
330 471 : myAbortedEmits.insert(veh);
331 471 : }
332 :
333 : void
334 15073 : MSInsertionControl::retractDescheduleDeparture(const SUMOVehicle* veh) {
335 15073 : myAbortedEmits.erase(veh);
336 15073 : }
337 :
338 :
339 : void
340 2929 : MSInsertionControl::alreadyDeparted(SUMOVehicle* veh) {
341 2929 : myPendingEmits.erase(std::remove(myPendingEmits.begin(), myPendingEmits.end(), veh), myPendingEmits.end());
342 2929 : myAllVeh.remove(veh);
343 2929 : }
344 :
345 :
346 : void
347 6 : MSInsertionControl::clearPendingVehicles(const std::string& route) {
348 : //clear out the refused vehicle list, deleting the vehicles entirely
349 : MSVehicleContainer::VehicleVector::iterator veh;
350 11 : for (veh = myPendingEmits.begin(); veh != myPendingEmits.end();) {
351 5 : if ((*veh)->getRoute().getID() == route || route == "") {
352 5 : myVehicleControl.deleteVehicle(*veh, true);
353 5 : veh = myPendingEmits.erase(veh);
354 : } else {
355 : ++veh;
356 : }
357 : }
358 6 : }
359 :
360 :
361 : int
362 0 : MSInsertionControl::getPendingEmits(const MSLane* lane) {
363 0 : const MSNet* net = MSNet::getInstance();
364 0 : if (net->getCurrentTimeStep() != myPendingEmitsUpdateTime) {
365 0 : net->lockPendingEmits();
366 : // updated pending emits (only once per time step)
367 : myPendingEmitsForLane.clear();
368 0 : for (const SUMOVehicle* const veh : myPendingEmits) {
369 0 : const MSLane* const vlane = veh->getLane();
370 0 : if (vlane != nullptr) {
371 0 : myPendingEmitsForLane[vlane]++;
372 : } else {
373 : // no (tentative) departLane was set, increase count for all
374 : // lanes of the depart edge
375 0 : for (const MSLane* const l : veh->getEdge()->getLanes()) {
376 0 : myPendingEmitsForLane[l]++;
377 : }
378 : }
379 : }
380 0 : myPendingEmitsUpdateTime = MSNet::getInstance()->getCurrentTimeStep();
381 0 : net->unlockPendingEmits();
382 : }
383 0 : return myPendingEmitsForLane[lane];
384 : }
385 :
386 :
387 : void
388 4847 : MSInsertionControl::adaptIntermodalRouter(MSTransportableRouter& router) const {
389 : // fill the public transport router with pre-parsed public transport lines
390 6851 : for (const Flow& f : myFlows) {
391 2004 : if (f.pars->line != "") {
392 511 : ConstMSRoutePtr const route = MSRoute::dictionary(f.pars->routeid);
393 511 : router.getNetwork()->addSchedule(*f.pars, route == nullptr ? nullptr : &route->getStops());
394 : }
395 : }
396 4847 : }
397 :
398 :
399 : void
400 535 : MSInsertionControl::saveState(OutputDevice& out) {
401 : // save flow states
402 629 : for (const Flow& flow : myFlows) {
403 94 : flow.pars->write(out, OptionsCont::getOptions(), SUMO_TAG_FLOWSTATE,
404 94 : flow.pars->vtypeid == DEFAULT_VTYPE_ID ? "" : flow.pars->vtypeid);
405 94 : if (flow.pars->repetitionProbability <= 0) {
406 80 : out.writeAttr(SUMO_ATTR_NEXT, STEPS2TIME(flow.pars->repetitionTotalOffset));
407 : }
408 94 : out.writeAttr(SUMO_ATTR_ROUTE, flow.pars->routeid);
409 94 : out.writeAttr(SUMO_ATTR_DONE, flow.pars->repetitionsDone);
410 94 : out.writeAttr(SUMO_ATTR_INDEX, flow.index);
411 94 : if (flow.pars->wasSet(VEHPARS_FORCE_REROUTE)) {
412 30 : out.writeAttr(SUMO_ATTR_REROUTE, true);
413 : }
414 108 : for (const SUMOVehicleParameter::Stop& stop : flow.pars->stops) {
415 14 : stop.write(out);
416 : }
417 188 : out.closeTag();
418 : }
419 535 : }
420 :
421 :
422 : void
423 162 : MSInsertionControl::clearState() {
424 162 : for (const Flow& f : myFlows) {
425 0 : delete (f.pars);
426 : }
427 : myFlows.clear();
428 : myFlowIDs.clear();
429 162 : myAllVeh.clearState();
430 : myPendingEmits.clear();
431 : myEmitCandidates.clear();
432 162 : myAbortedEmits.clear();
433 : // myPendingEmitsForLane must not be cleared since it updates itself on the next call
434 162 : }
435 :
436 :
437 : SUMOTime
438 5230828 : MSInsertionControl::computeRandomDepartOffset() const {
439 5230828 : if (myMaxRandomDepartOffset > 0) {
440 : // round to the closest usable simulation step
441 90 : return DELTA_T * ((RandHelper::rand(myMaxRandomDepartOffset, MSRouteHandler::getParsingRNG()) + DELTA_T / 2) / DELTA_T);
442 : }
443 : return 0;
444 : }
445 :
446 : const SUMOVehicleParameter*
447 40 : MSInsertionControl::getFlowPars(const std::string& id) const {
448 : if (hasFlow(id)) {
449 40 : for (const Flow& f : myFlows) {
450 40 : if (f.pars->id == id) {
451 : return f.pars;
452 : }
453 : }
454 : }
455 : return nullptr;
456 : }
457 :
458 : SUMOVehicle*
459 808 : MSInsertionControl::getLastFlowVehicle(const std::string& id) const {
460 : const auto it = myFlowIDs.find(id);
461 808 : if (it != myFlowIDs.end()) {
462 1616 : const std::string vehID = id + "." + toString(it->second);
463 808 : return MSNet::getInstance()->getVehicleControl().getVehicle(vehID);
464 : }
465 : return nullptr;
466 : }
467 :
468 :
469 : bool
470 10550 : MSInsertionControl::hasTaxiFlow() const {
471 21100 : SumoRNG tmp("tmp");
472 18256 : for (const Flow& flow : myFlows) {
473 15492 : if (flow.scale != 0 &&
474 38730 : (StringUtils::toBool(flow.pars->getParameter("has.taxi.device", "false"))
475 7746 : || hasTaxiDeviceType(flow.pars->vtypeid, tmp))) {
476 : return true;
477 : }
478 : }
479 : return false;
480 : }
481 :
482 :
483 : bool
484 7746 : MSInsertionControl::hasTaxiDeviceType(const std::string& vtypeId, SumoRNG& rng) {
485 7746 : MSVehicleControl& vehControl = MSNet::getInstance()->getVehicleControl();
486 7746 : const MSVehicleType* vtype = vehControl.getVType(vtypeId, &rng);
487 15492 : return StringUtils::toBool(vtype->getParameter().getParameter("has.taxi.device", "false"));
488 : }
489 :
490 : /****************************************************************************/
|