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