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 MSVehicleControl.cpp
11 /// @author Daniel Krajzewicz
12 /// @author Jakob Erdmann
13 /// @author Michael Behrisch
14 /// @date Wed, 10. Dec 2003
15 /// @version $Id$
16 ///
17 // The class responsible for building and deletion of vehicles
18 /****************************************************************************/
19
20
21 // ===========================================================================
22 // included modules
23 // ===========================================================================
24 #include <config.h>
25
26 #include "MSVehicleControl.h"
27 #include "MSVehicle.h"
28 #include "MSLane.h"
29 #include "MSEdge.h"
30 #include "MSNet.h"
31 #include "MSRouteHandler.h"
32 #include <microsim/devices/MSVehicleDevice.h>
33 #include <utils/common/FileHelpers.h>
34 #include <utils/common/Named.h>
35 #include <utils/common/RGBColor.h>
36 #include <utils/vehicle/SUMOVTypeParameter.h>
37 #include <utils/iodevices/BinaryInputDevice.h>
38 #include <utils/iodevices/OutputDevice.h>
39 #include <utils/options/OptionsCont.h>
40 #include <utils/router/IntermodalRouter.h>
41 #ifdef HAVE_FOX
42 #include <utils/foxtools/FXConditionalLock.h>
43 #endif
44
45
46 // ===========================================================================
47 // member method definitions
48 // ===========================================================================
MSVehicleControl()49 MSVehicleControl::MSVehicleControl() :
50 myLoadedVehNo(0),
51 myRunningVehNo(0),
52 myEndedVehNo(0),
53 myDiscarded(0),
54 myCollisions(0),
55 myTeleportsJam(0),
56 myTeleportsYield(0),
57 myTeleportsWrongLane(0),
58 myEmergencyStops(0),
59 myTotalDepartureDelay(0),
60 myTotalTravelTime(0),
61 myDefaultVTypeMayBeDeleted(true),
62 myDefaultPedTypeMayBeDeleted(true),
63 myDefaultBikeTypeMayBeDeleted(true),
64 myWaitingForPerson(0),
65 myWaitingForContainer(0),
66 myMaxSpeedFactor(1),
67 myMinDeceleration(SUMOVTypeParameter::getDefaultDecel(SVC_IGNORING)),
68 myPendingRemovals(MSGlobals::gNumSimThreads > 1) {
69 SUMOVTypeParameter defType(DEFAULT_VTYPE_ID, SVC_PASSENGER);
70 myVTypeDict[DEFAULT_VTYPE_ID] = MSVehicleType::build(defType);
71 SUMOVTypeParameter defPedType(DEFAULT_PEDTYPE_ID, SVC_PEDESTRIAN);
72 defPedType.parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
73 myVTypeDict[DEFAULT_PEDTYPE_ID] = MSVehicleType::build(defPedType);
74 SUMOVTypeParameter defBikeType(DEFAULT_BIKETYPE_ID, SVC_BICYCLE);
75 defBikeType.parametersSet |= VTYPEPARS_VEHICLECLASS_SET;
76 myVTypeDict[DEFAULT_BIKETYPE_ID] = MSVehicleType::build(defBikeType);
77 OptionsCont& oc = OptionsCont::getOptions();
78 myScale = oc.getFloat("scale");
79 }
80
81
~MSVehicleControl()82 MSVehicleControl::~MSVehicleControl() {
83 // delete vehicles
84 for (VehicleDictType::iterator i = myVehicleDict.begin(); i != myVehicleDict.end(); ++i) {
85 delete (*i).second;
86 }
87 myVehicleDict.clear();
88 // delete vehicle type distributions
89 for (VTypeDistDictType::iterator i = myVTypeDistDict.begin(); i != myVTypeDistDict.end(); ++i) {
90 delete (*i).second;
91 }
92 myVTypeDistDict.clear();
93 // delete vehicle types
94 for (VTypeDictType::iterator i = myVTypeDict.begin(); i != myVTypeDict.end(); ++i) {
95 //delete(*i).second;
96 }
97 myVTypeDict.clear();
98 }
99
100
101 SUMOVehicle*
buildVehicle(SUMOVehicleParameter * defs,const MSRoute * route,MSVehicleType * type,const bool ignoreStopErrors,const bool fromRouteFile)102 MSVehicleControl::buildVehicle(SUMOVehicleParameter* defs,
103 const MSRoute* route, MSVehicleType* type,
104 const bool ignoreStopErrors, const bool fromRouteFile) {
105 myLoadedVehNo++;
106 MSVehicle* built = new MSVehicle(defs, route, type, type->computeChosenSpeedDeviation(fromRouteFile ? MSRouteHandler::getParsingRNG() : nullptr));
107 built->addStops(ignoreStopErrors);
108 MSNet::getInstance()->informVehicleStateListener(built, MSNet::VEHICLE_STATE_BUILT);
109 return built;
110 }
111
112
113 void
scheduleVehicleRemoval(SUMOVehicle * veh)114 MSVehicleControl::scheduleVehicleRemoval(SUMOVehicle* veh) {
115 assert(myRunningVehNo > 0);
116 myPendingRemovals.push_back(veh);
117 }
118
119
120 void
removePending()121 MSVehicleControl::removePending() {
122 #ifdef HAVE_FOX
123 std::vector<SUMOVehicle*>& vehs = myPendingRemovals.getContainer();
124 #else
125 std::vector<SUMOVehicle*>& vehs = myPendingRemovals;
126 #endif
127 std::sort(vehs.begin(), vehs.end(), ComparatorNumericalIdLess());
128 for (SUMOVehicle* const veh : vehs) {
129 myTotalTravelTime += STEPS2TIME(MSNet::getInstance()->getCurrentTimeStep() - veh->getDeparture());
130 myRunningVehNo--;
131 MSNet::getInstance()->informVehicleStateListener(veh, MSNet::VEHICLE_STATE_ARRIVED);
132 for (MSVehicleDevice* const dev : veh->getDevices()) {
133 dev->generateOutput();
134 }
135 if (OptionsCont::getOptions().isSet("tripinfo-output")) {
136 // close tag after tripinfo (possibly including emissions from another device) have been written
137 OutputDevice::getDeviceByOption("tripinfo-output").closeTag();
138 }
139 deleteVehicle(veh);
140 }
141 vehs.clear();
142 #ifdef HAVE_FOX
143 myPendingRemovals.unlock();
144 #endif
145 }
146
147
148 void
vehicleDeparted(const SUMOVehicle & v)149 MSVehicleControl::vehicleDeparted(const SUMOVehicle& v) {
150 ++myRunningVehNo;
151 myTotalDepartureDelay += STEPS2TIME(v.getDeparture() - STEPFLOOR(v.getParameter().depart));
152 MSNet::getInstance()->informVehicleStateListener(&v, MSNet::VEHICLE_STATE_DEPARTED);
153 myMaxSpeedFactor = MAX2(myMaxSpeedFactor, v.getChosenSpeedFactor());
154 if ((v.getVClass() & (SVC_SHIP | SVC_PEDESTRIAN | SVC_RAIL | SVC_RAIL_ELECTRIC | SVC_RAIL_URBAN)) == 0) {
155 // only worry about deceleration of road users
156 myMinDeceleration = MIN2(myMinDeceleration, v.getVehicleType().getCarFollowModel().getMaxDecel());
157 }
158 }
159
160
161 void
setState(int runningVehNo,int loadedVehNo,int endedVehNo,double totalDepartureDelay,double totalTravelTime)162 MSVehicleControl::setState(int runningVehNo, int loadedVehNo, int endedVehNo, double totalDepartureDelay, double totalTravelTime) {
163 myRunningVehNo = runningVehNo;
164 myLoadedVehNo = loadedVehNo;
165 myEndedVehNo = endedVehNo;
166 myTotalDepartureDelay = totalDepartureDelay;
167 myTotalTravelTime = totalTravelTime;
168 }
169
170
171 void
saveState(OutputDevice & out)172 MSVehicleControl::saveState(OutputDevice& out) {
173 out.openTag(SUMO_TAG_DELAY);
174 out.writeAttr(SUMO_ATTR_NUMBER, myRunningVehNo);
175 out.writeAttr(SUMO_ATTR_BEGIN, myLoadedVehNo);
176 out.writeAttr(SUMO_ATTR_END, myEndedVehNo);
177 out.writeAttr(SUMO_ATTR_DEPART, myTotalDepartureDelay);
178 out.writeAttr(SUMO_ATTR_TIME, myTotalTravelTime).closeTag();
179 // save vehicle types
180 for (VTypeDictType::iterator it = myVTypeDict.begin(); it != myVTypeDict.end(); ++it) {
181 it->second->getParameter().write(out);
182 }
183 for (VTypeDistDictType::iterator it = myVTypeDistDict.begin(); it != myVTypeDistDict.end(); ++it) {
184 out.openTag(SUMO_TAG_VTYPE_DISTRIBUTION).writeAttr(SUMO_ATTR_ID, it->first);
185 out.writeAttr(SUMO_ATTR_VTYPES, (*it).second->getVals());
186 out.writeAttr(SUMO_ATTR_PROBS, (*it).second->getProbs());
187 out.closeTag();
188 }
189 for (VehicleDictType::iterator it = myVehicleDict.begin(); it != myVehicleDict.end(); ++it) {
190 (*it).second->saveState(out);
191 }
192 }
193
194
195 bool
addVehicle(const std::string & id,SUMOVehicle * v)196 MSVehicleControl::addVehicle(const std::string& id, SUMOVehicle* v) {
197 VehicleDictType::iterator it = myVehicleDict.find(id);
198 if (it == myVehicleDict.end()) {
199 // id not in myVehicleDict.
200 myVehicleDict[id] = v;
201 const SUMOVehicleParameter& pars = v->getParameter();
202 if (pars.departProcedure == DEPART_TRIGGERED || pars.departProcedure == DEPART_CONTAINER_TRIGGERED) {
203 const MSEdge* const firstEdge = v->getRoute().getEdges()[0];
204 if (!MSGlobals::gUseMesoSim) {
205 // position will be checked against person position later
206 static_cast<MSVehicle*>(v)->setTentativeLaneAndPosition(firstEdge->getLanes()[0], v->getParameter().departPos);
207 }
208 addWaiting(v->getRoute().getEdges().front(), v);
209 registerOneWaiting(pars.departProcedure == DEPART_TRIGGERED);
210 }
211 if (pars.line != "" && pars.repetitionNumber < 0) {
212 myPTVehicles.push_back(v);
213 }
214 return true;
215 }
216 return false;
217 }
218
219
220 SUMOVehicle*
getVehicle(const std::string & id) const221 MSVehicleControl::getVehicle(const std::string& id) const {
222 VehicleDictType::const_iterator it = myVehicleDict.find(id);
223 if (it == myVehicleDict.end()) {
224 return nullptr;
225 }
226 return it->second;
227 }
228
229
230 void
deleteVehicle(SUMOVehicle * veh,bool discard)231 MSVehicleControl::deleteVehicle(SUMOVehicle* veh, bool discard) {
232 myEndedVehNo++;
233 if (discard) {
234 myDiscarded++;
235 }
236 if (veh != nullptr) {
237 myVehicleDict.erase(veh->getID());
238 }
239 auto ptVehIt = std::find(myPTVehicles.begin(), myPTVehicles.end(), veh);
240 if (ptVehIt != myPTVehicles.end()) {
241 myPTVehicles.erase(ptVehIt);
242 }
243 delete veh;
244 }
245
246
247 bool
checkVType(const std::string & id)248 MSVehicleControl::checkVType(const std::string& id) {
249 if (id == DEFAULT_VTYPE_ID) {
250 if (myDefaultVTypeMayBeDeleted) {
251 delete myVTypeDict[id];
252 myVTypeDict.erase(myVTypeDict.find(id));
253 myDefaultVTypeMayBeDeleted = false;
254 } else {
255 return false;
256 }
257 } else if (id == DEFAULT_PEDTYPE_ID) {
258 if (myDefaultPedTypeMayBeDeleted) {
259 delete myVTypeDict[id];
260 myVTypeDict.erase(myVTypeDict.find(id));
261 myDefaultPedTypeMayBeDeleted = false;
262 } else {
263 return false;
264 }
265 } else if (id == DEFAULT_BIKETYPE_ID) {
266 if (myDefaultBikeTypeMayBeDeleted) {
267 delete myVTypeDict[id];
268 myVTypeDict.erase(myVTypeDict.find(id));
269 myDefaultBikeTypeMayBeDeleted = false;
270 } else {
271 return false;
272 }
273 } else {
274 if (myVTypeDict.find(id) != myVTypeDict.end() || myVTypeDistDict.find(id) != myVTypeDistDict.end()) {
275 return false;
276 }
277 }
278 return true;
279 }
280
281 bool
addVType(MSVehicleType * vehType)282 MSVehicleControl::addVType(MSVehicleType* vehType) {
283 if (checkVType(vehType->getID())) {
284 myVTypeDict[vehType->getID()] = vehType;
285 return true;
286 }
287 return false;
288 }
289
290
291 void
removeVType(const MSVehicleType * vehType)292 MSVehicleControl::removeVType(const MSVehicleType* vehType) {
293 assert(vehType != 0);
294 assert(myVTypeDict.find(vehType->getID()) != myVTypeDict.end());
295 myVTypeDict.erase(vehType->getID());
296 if (myVTypeToDist.find(vehType->getID()) != myVTypeToDist.end()) {
297 myVTypeToDist.erase(vehType->getID());
298 }
299 delete vehType;
300 }
301
302
303 bool
addVTypeDistribution(const std::string & id,RandomDistributor<MSVehicleType * > * vehTypeDistribution)304 MSVehicleControl::addVTypeDistribution(const std::string& id, RandomDistributor<MSVehicleType*>* vehTypeDistribution) {
305 if (checkVType(id)) {
306 myVTypeDistDict[id] = vehTypeDistribution;
307 std::vector<MSVehicleType*> vehTypes = vehTypeDistribution->getVals();
308 for (auto vehType : vehTypes) {
309 if (myVTypeToDist.find(vehType->getID()) != myVTypeToDist.end()) {
310 myVTypeToDist[vehType->getID()].insert(id);
311 } else {
312 myVTypeToDist[vehType->getID()] = { id };
313 }
314 }
315 return true;
316 }
317 return false;
318 }
319
320
321 bool
hasVType(const std::string & id) const322 MSVehicleControl::hasVType(const std::string& id) const {
323 return myVTypeDict.count(id) > 0 || myVTypeDistDict.count(id) > 0;
324 }
325
326
327 bool
hasVTypeDistribution(const std::string & id) const328 MSVehicleControl::hasVTypeDistribution(const std::string& id) const {
329 return myVTypeDistDict.count(id) > 0;
330 }
331
332
333 MSVehicleType*
getVType(const std::string & id,std::mt19937 * rng)334 MSVehicleControl::getVType(const std::string& id, std::mt19937* rng) {
335 VTypeDictType::iterator it = myVTypeDict.find(id);
336 if (it == myVTypeDict.end()) {
337 VTypeDistDictType::iterator it2 = myVTypeDistDict.find(id);
338 if (it2 == myVTypeDistDict.end()) {
339 return nullptr;
340 }
341 return it2->second->get(rng);
342 }
343 if (id == DEFAULT_VTYPE_ID) {
344 myDefaultVTypeMayBeDeleted = false;
345 } else if (id == DEFAULT_PEDTYPE_ID) {
346 myDefaultPedTypeMayBeDeleted = false;
347 }
348 return it->second;
349 }
350
351
352 void
insertVTypeIDs(std::vector<std::string> & into) const353 MSVehicleControl::insertVTypeIDs(std::vector<std::string>& into) const {
354 into.reserve(into.size() + myVTypeDict.size() + myVTypeDistDict.size());
355 for (VTypeDictType::const_iterator i = myVTypeDict.begin(); i != myVTypeDict.end(); ++i) {
356 into.push_back((*i).first);
357 }
358 for (VTypeDistDictType::const_iterator i = myVTypeDistDict.begin(); i != myVTypeDistDict.end(); ++i) {
359 into.push_back((*i).first);
360 }
361 }
362
363
364 std::set<std::string>
getVTypeDistributionMembership(const std::string & id) const365 MSVehicleControl::getVTypeDistributionMembership(const std::string& id) const {
366 std::map<std::string, std::set<std::string>>::const_iterator it = myVTypeToDist.find(id);
367 if (it == myVTypeToDist.end()) {
368 return std::set<std::string>();
369 }
370 return it->second;
371 }
372
373
374 void
addWaiting(const MSEdge * const edge,SUMOVehicle * vehicle)375 MSVehicleControl::addWaiting(const MSEdge* const edge, SUMOVehicle* vehicle) {
376 if (myWaiting.find(edge) == myWaiting.end()) {
377 myWaiting[edge] = std::vector<SUMOVehicle*>();
378 }
379 myWaiting[edge].push_back(vehicle);
380 }
381
382
383 void
removeWaiting(const MSEdge * const edge,const SUMOVehicle * vehicle)384 MSVehicleControl::removeWaiting(const MSEdge* const edge, const SUMOVehicle* vehicle) {
385 if (myWaiting.find(edge) != myWaiting.end()) {
386 std::vector<SUMOVehicle*>::iterator it = std::find(myWaiting[edge].begin(), myWaiting[edge].end(), vehicle);
387 if (it != myWaiting[edge].end()) {
388 myWaiting[edge].erase(it);
389 }
390 }
391 }
392
393
394 SUMOVehicle*
getWaitingVehicle(MSTransportable * transportable,const MSEdge * const edge,const double position)395 MSVehicleControl::getWaitingVehicle(MSTransportable* transportable, const MSEdge* const edge, const double position) {
396 if (myWaiting.find(edge) != myWaiting.end()) {
397 // for every vehicle waiting vehicle at this edge
398 std::vector<SUMOVehicle*> waitingTooFarAway;
399 for (SUMOVehicle* vehicle : myWaiting[edge]) {
400 double vehiclePosition = vehicle->getPositionOnLane();
401 // if the line of the vehicle is contained in the set of given lines and the vehicle is stopped and is positioned
402 // in the interval [position - t, position + t] for a tolerance t=10
403 if (transportable->isWaitingFor(vehicle)) {
404 if ((position - 10 <= vehiclePosition) && (vehiclePosition <= position + 10)) {
405 return vehicle;
406 } else if (vehicle->isStoppedTriggered() ||
407 vehicle->getParameter().departProcedure == DEPART_TRIGGERED) {
408 // maybe we are within the range of the stop
409 if (vehicle->isStoppedInRange(position)) {
410 return vehicle;
411 } else {
412 waitingTooFarAway.push_back(vehicle);
413 }
414 }
415 }
416 }
417 for (SUMOVehicle* vehicle : waitingTooFarAway) {
418 WRITE_WARNING(transportable->getID() + " at edge '" + edge->getID() + "' position " + toString(position) + " cannot use waiting vehicle '"
419 + vehicle->getID() + "' at position " + toString(vehicle->getPositionOnLane()) + " because it is too far away.");
420 }
421 }
422 return nullptr;
423 }
424
425
426 void
abortWaiting()427 MSVehicleControl::abortWaiting() {
428 for (VehicleDictType::iterator i = myVehicleDict.begin(); i != myVehicleDict.end(); ++i) {
429 WRITE_WARNING("Vehicle " + i->first + " aborted waiting for a person or a container that will never come.");
430 }
431 }
432
433
434 int
getHaltingVehicleNo() const435 MSVehicleControl::getHaltingVehicleNo() const {
436 int result = 0;
437 for (MSVehicleControl::constVehIt it = loadedVehBegin(); it != loadedVehEnd(); ++it) {
438 const SUMOVehicle* veh = it->second;
439 if ((veh->isOnRoad() || veh->isRemoteControlled()) && veh->getSpeed() < SUMO_const_haltingSpeed) {
440 result++;
441 }
442 }
443 return result;
444 }
445
446
447
448 std::pair<double, double>
getVehicleMeanSpeeds() const449 MSVehicleControl::getVehicleMeanSpeeds() const {
450 double speedSum = 0;
451 double relSpeedSum = 0;
452 int count = 0;
453 for (MSVehicleControl::constVehIt it = loadedVehBegin(); it != loadedVehEnd(); ++it) {
454 const SUMOVehicle* veh = it->second;
455 if ((veh->isOnRoad() || veh->isRemoteControlled()) && !veh->isStopped()) {
456 count++;
457 speedSum += veh->getSpeed();
458 relSpeedSum += veh->getSpeed() / veh->getEdge()->getSpeedLimit();
459 }
460 }
461 if (count > 0) {
462 return std::make_pair(speedSum / count, relSpeedSum / count);
463 } else {
464 return std::make_pair(-1, -1);
465 }
466 }
467
468
469 int
getQuota(double frac) const470 MSVehicleControl::getQuota(double frac) const {
471 frac = frac < 0 ? myScale : frac;
472 if (frac < 0 || frac == 1.) {
473 return 1;
474 }
475 // the vehicle in question has already been loaded, hence the '-1'
476 const int loaded = frac > 1. ? (int)(myLoadedVehNo / frac) : myLoadedVehNo - 1;
477 const int base = (int)frac;
478 const int resolution = 1000;
479 const int intFrac = (int)floor((frac - base) * resolution + 0.5);
480 // apply % twice to avoid integer overflow
481 if (((loaded % resolution) * intFrac) % resolution < intFrac) {
482 return base + 1;
483 }
484 return base;
485 }
486
487 int
getTeleportCount() const488 MSVehicleControl::getTeleportCount() const {
489 return (MSLane::teleportOnCollision() ? myCollisions : 0) + myTeleportsJam + myTeleportsYield + myTeleportsWrongLane;
490 }
491
492
493 void
adaptIntermodalRouter(MSNet::MSIntermodalRouter & router) const494 MSVehicleControl::adaptIntermodalRouter(MSNet::MSIntermodalRouter& router) const {
495 for (const SUMOVehicle* const veh : myPTVehicles) {
496 // add single vehicles with line attribute which are not part of a flow
497 const MSRoute* const route = MSRoute::dictionary(veh->getParameter().routeid);
498 router.getNetwork()->addSchedule(veh->getParameter(), route == nullptr ? nullptr : &route->getStops());
499 }
500 }
501
502
503 /****************************************************************************/
504
505