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 MSNet.cpp
11 /// @author Christian Roessel
12 /// @author Daniel Krajzewicz
13 /// @author Jakob Erdmann
14 /// @author Clemens Honomichl
15 /// @author Eric Nicolay
16 /// @author Mario Krumnow
17 /// @author Michael Behrisch
18 /// @author Mario Krumnow
19 /// @author Christoph Sommer
20 /// @date Tue, 06 Mar 2001
21 /// @version $Id$
22 ///
23 // The simulated network and simulation perfomer
24 /****************************************************************************/
25
26
27 // ===========================================================================
28 // included modules
29 // ===========================================================================
30 #include <config.h>
31
32 #ifdef HAVE_VERSION_H
33 #include <version.h>
34 #endif
35
36 #include <string>
37 #include <iostream>
38 #include <sstream>
39 #include <typeinfo>
40 #include <algorithm>
41 #include <cassert>
42 #include <vector>
43 #include <ctime>
44
45 #include "trigger/MSTrigger.h"
46 #include "trigger/MSCalibrator.h"
47 #include "traffic_lights/MSTLLogicControl.h"
48 #include "MSVehicleControl.h"
49 #include <utils/common/MsgHandler.h>
50 #include <utils/common/ToString.h>
51 #include <utils/common/SysUtils.h>
52 #include <utils/common/UtilExceptions.h>
53 #include <utils/common/WrappingCommand.h>
54 #include <utils/common/SystemFrame.h>
55 #include <utils/geom/GeoConvHelper.h>
56 #include <utils/iodevices/OutputDevice_File.h>
57 #include <utils/iodevices/OutputDevice.h>
58 #include <utils/options/OptionsCont.h>
59 #include <utils/options/OptionsIO.h>
60 #include <utils/shapes/ShapeContainer.h>
61 #include <utils/router/DijkstraRouter.h>
62 #include <utils/router/AStarRouter.h>
63 #include <utils/router/IntermodalRouter.h>
64 #include <utils/router/PedestrianRouter.h>
65 #include <utils/vehicle/SUMORouteLoaderControl.h>
66 #include <utils/xml/XMLSubSys.h>
67 #include <traci-server/TraCIServer.h>
68 #include <libsumo/Simulation.h>
69 #include <mesosim/MELoop.h>
70 #include <microsim/output/MSDetectorControl.h>
71 #include <microsim/MSCModel_NonInteracting.h>
72 #include <microsim/MSVehicleTransfer.h>
73 #include <microsim/devices/MSRoutingEngine.h>
74 #include <microsim/devices/MSDevice_Vehroutes.h>
75 #include <microsim/devices/MSDevice_Tripinfo.h>
76 #include <microsim/devices/MSDevice_BTsender.h>
77 #include <microsim/devices/MSDevice_SSM.h>
78 #include <microsim/devices/MSDevice_ToC.h>
79 #include <microsim/output/MSBatteryExport.h>
80 #include <microsim/output/MSEmissionExport.h>
81 #include <microsim/output/MSFCDExport.h>
82 #include <microsim/output/MSFullExport.h>
83 #include <microsim/output/MSQueueExport.h>
84 #include <microsim/output/MSVTKExport.h>
85 #include <microsim/output/MSXMLRawOut.h>
86 #include <microsim/output/MSAmitranTrajectories.h>
87 #include <microsim/output/MSStopOut.h>
88 #include <microsim/pedestrians/MSPModel.h>
89 #include <microsim/pedestrians/MSPerson.h>
90 #include <microsim/traffic_lights/MSTrafficLightLogic.h>
91 #include <microsim/trigger/MSChargingStation.h>
92 #include <utils/router/FareModul.h>
93
94 #include "MSTransportableControl.h"
95 #include "MSEdgeControl.h"
96 #include "MSJunctionControl.h"
97 #include "MSInsertionControl.h"
98 #include "MSDynamicShapeUpdater.h"
99 #include "MSEventControl.h"
100 #include "MSEdge.h"
101 #include "MSJunction.h"
102 #include "MSJunctionLogic.h"
103 #include "MSLane.h"
104 #include "MSVehicleTransfer.h"
105 #include "MSRoute.h"
106 #include "MSGlobals.h"
107 #include "MSContainer.h"
108 #include "MSEdgeWeightsStorage.h"
109 #include "MSStateHandler.h"
110 #include "MSFrame.h"
111 #include "MSParkingArea.h"
112 #include "MSStoppingPlace.h"
113 #include "MSNet.h"
114
115
116 // ===========================================================================
117 // debug constants
118 // ===========================================================================
119 //#define DEBUG_SIMSTEP
120
121
122 // ===========================================================================
123 // static member definitions
124 // ===========================================================================
125 MSNet* MSNet::myInstance = nullptr;
126
127 const std::string MSNet::STAGE_EVENTS("events");
128 const std::string MSNet::STAGE_MOVEMENTS("move");
129 const std::string MSNet::STAGE_LANECHANGE("laneChange");
130 const std::string MSNet::STAGE_INSERTIONS("insertion");
131
132 // ===========================================================================
133 // static member method definitions
134 // ===========================================================================
135 double
getEffort(const MSEdge * const e,const SUMOVehicle * const v,double t)136 MSNet::getEffort(const MSEdge* const e, const SUMOVehicle* const v, double t) {
137 double value;
138 const MSVehicle* const veh = dynamic_cast<const MSVehicle* const>(v);
139 if (veh != nullptr && veh->getWeightsStorage().retrieveExistingEffort(e, t, value)) {
140 return value;
141 }
142 if (getInstance()->getWeightsStorage().retrieveExistingEffort(e, t, value)) {
143 return value;
144 }
145 return 0;
146 }
147
148
149 double
getTravelTime(const MSEdge * const e,const SUMOVehicle * const v,double t)150 MSNet::getTravelTime(const MSEdge* const e, const SUMOVehicle* const v, double t) {
151 double value;
152 const MSVehicle* const veh = dynamic_cast<const MSVehicle* const>(v);
153 if (veh != nullptr && veh->getWeightsStorage().retrieveExistingTravelTime(e, t, value)) {
154 return value;
155 }
156 if (getInstance()->getWeightsStorage().retrieveExistingTravelTime(e, t, value)) {
157 return value;
158 }
159 return e->getMinimumTravelTime(v);
160 }
161
162
163 // ---------------------------------------------------------------------------
164 // MSNet - methods
165 // ---------------------------------------------------------------------------
166 MSNet*
getInstance(void)167 MSNet::getInstance(void) {
168 if (myInstance != nullptr) {
169 return myInstance;
170 }
171 throw ProcessError("A network was not yet constructed.");
172 }
173
174 void
initStatic()175 MSNet::initStatic() {
176 if (!MSGlobals::gUseMesoSim) {
177 MSVehicle::Influencer::init();
178 }
179 }
180
181 void
cleanupStatic()182 MSNet::cleanupStatic() {
183 if (!MSGlobals::gUseMesoSim) {
184 MSVehicle::Influencer::cleanup();
185 }
186 }
187
188
MSNet(MSVehicleControl * vc,MSEventControl * beginOfTimestepEvents,MSEventControl * endOfTimestepEvents,MSEventControl * insertionEvents,ShapeContainer * shapeCont)189 MSNet::MSNet(MSVehicleControl* vc, MSEventControl* beginOfTimestepEvents,
190 MSEventControl* endOfTimestepEvents,
191 MSEventControl* insertionEvents,
192 ShapeContainer* shapeCont):
193 myAmInterrupted(false),
194 myVehiclesMoved(0),
195 myHavePermissions(false),
196 myHasInternalLinks(false),
197 myHasElevation(false),
198 myHasPedestrianNetwork(false),
199 myEdgeDataEndTime(-1),
200 myRouterTT(nullptr),
201 myRouterEffort(nullptr),
202 myPedestrianRouter(nullptr),
203 myDynamicShapeUpdater(nullptr) {
204 if (myInstance != nullptr) {
205 throw ProcessError("A network was already constructed.");
206 }
207 OptionsCont& oc = OptionsCont::getOptions();
208 myStep = string2time(oc.getString("begin"));
209 myMaxTeleports = oc.getInt("max-num-teleports");
210 myLogExecutionTime = !oc.getBool("no-duration-log");
211 myLogStepNumber = !oc.getBool("no-step-log");
212 myInserter = new MSInsertionControl(*vc, string2time(oc.getString("max-depart-delay")), oc.getBool("eager-insert"), oc.getInt("max-num-vehicles"),
213 string2time(oc.getString("random-depart-offset")));
214 myVehicleControl = vc;
215 myDetectorControl = new MSDetectorControl();
216 myEdges = nullptr;
217 myJunctions = nullptr;
218 myRouteLoaders = nullptr;
219 myLogics = nullptr;
220 myPersonControl = nullptr;
221 myContainerControl = nullptr;
222 myEdgeWeights = nullptr;
223 myShapeContainer = shapeCont == nullptr ? new ShapeContainer() : shapeCont;
224
225 myBeginOfTimestepEvents = beginOfTimestepEvents;
226 myEndOfTimestepEvents = endOfTimestepEvents;
227 myInsertionEvents = insertionEvents;
228 myLanesRTree.first = false;
229
230 if (MSGlobals::gUseMesoSim) {
231 MSGlobals::gMesoNet = new MELoop(string2time(oc.getString("meso-recheck")));
232 }
233 myInstance = this;
234 initStatic();
235 }
236
237
238 void
closeBuilding(const OptionsCont & oc,MSEdgeControl * edges,MSJunctionControl * junctions,SUMORouteLoaderControl * routeLoaders,MSTLLogicControl * tlc,std::vector<SUMOTime> stateDumpTimes,std::vector<std::string> stateDumpFiles,bool hasInternalLinks,bool hasNeighs,bool lefthand,double version)239 MSNet::closeBuilding(const OptionsCont& oc, MSEdgeControl* edges, MSJunctionControl* junctions,
240 SUMORouteLoaderControl* routeLoaders,
241 MSTLLogicControl* tlc,
242 std::vector<SUMOTime> stateDumpTimes,
243 std::vector<std::string> stateDumpFiles,
244 bool hasInternalLinks,
245 bool hasNeighs,
246 bool lefthand,
247 double version) {
248 myEdges = edges;
249 myJunctions = junctions;
250 myRouteLoaders = routeLoaders;
251 myLogics = tlc;
252 // save the time the network state shall be saved at
253 myStateDumpTimes = stateDumpTimes;
254 myStateDumpFiles = stateDumpFiles;
255 myStateDumpPeriod = string2time(oc.getString("save-state.period"));
256 myStateDumpPrefix = oc.getString("save-state.prefix");
257 myStateDumpSuffix = oc.getString("save-state.suffix");
258
259 // initialise performance computation
260 mySimBeginMillis = SysUtils::getCurrentMillis();
261 myHasInternalLinks = hasInternalLinks;
262 if (hasNeighs && MSGlobals::gLateralResolution > 0) {
263 WRITE_WARNING("Opposite direction driving does not work together with the sublane model.");
264 }
265 myHasElevation = checkElevation();
266 myHasPedestrianNetwork = checkWalkingarea();
267 myLefthand = lefthand;
268 myVersion = version;
269 }
270
271
~MSNet()272 MSNet::~MSNet() {
273 cleanupStatic();
274 // delete controls
275 delete myJunctions;
276 delete myDetectorControl;
277 // delete mean data
278 delete myEdges;
279 delete myInserter;
280 delete myLogics;
281 delete myRouteLoaders;
282 if (myPersonControl != nullptr) {
283 delete myPersonControl;
284 }
285 if (myContainerControl != nullptr) {
286 delete myContainerControl;
287 }
288 delete myVehicleControl; // must happen after deleting transportables
289 // delete events late so that vehicles can get rid of references first
290 delete myBeginOfTimestepEvents;
291 myBeginOfTimestepEvents = nullptr;
292 delete myEndOfTimestepEvents;
293 myEndOfTimestepEvents = nullptr;
294 delete myInsertionEvents;
295 myInsertionEvents = nullptr;
296 delete myShapeContainer;
297 delete myEdgeWeights;
298 delete myRouterTT;
299 delete myRouterEffort;
300 delete myPedestrianRouter;
301 for (auto& router : myIntermodalRouter) {
302 delete router.second;
303 }
304 myIntermodalRouter.clear();
305 myLanesRTree.second.RemoveAll();
306 clearAll();
307 if (MSGlobals::gUseMesoSim) {
308 delete MSGlobals::gMesoNet;
309 }
310 myInstance = nullptr;
311 }
312
313
314 void
addRestriction(const std::string & id,const SUMOVehicleClass svc,const double speed)315 MSNet::addRestriction(const std::string& id, const SUMOVehicleClass svc, const double speed) {
316 myRestrictions[id][svc] = speed;
317 }
318
319
320 const std::map<SUMOVehicleClass, double>*
getRestrictions(const std::string & id) const321 MSNet::getRestrictions(const std::string& id) const {
322 std::map<std::string, std::map<SUMOVehicleClass, double> >::const_iterator i = myRestrictions.find(id);
323 if (i == myRestrictions.end()) {
324 return nullptr;
325 }
326 return &i->second;
327 }
328
329
330 MSNet::SimulationState
simulate(SUMOTime start,SUMOTime stop)331 MSNet::simulate(SUMOTime start, SUMOTime stop) {
332 // report the begin when wished
333 WRITE_MESSAGE("Simulation version " + std::string(VERSION_STRING) + " started with time: " + time2string(start));
334 // the simulation loop
335 SimulationState state = SIMSTATE_RUNNING;
336 // state loading may have changed the start time so we need to reinit it
337 myStep = start;
338 #ifdef HAVE_PYTHON
339 if (OptionsCont::getOptions().isSet("python-script")) {
340 TraCIServer::runEmbedded(OptionsCont::getOptions().getString("python-script"));
341 closeSimulation(start);
342 WRITE_MESSAGE("Simulation ended at time: " + time2string(getCurrentTimeStep()));
343 WRITE_MESSAGE("Reason: Script ended");
344 return state;
345 }
346 #endif
347 while (state == SIMSTATE_RUNNING) {
348 if (myLogStepNumber) {
349 preSimStepOutput();
350 }
351 simulationStep();
352 if (myLogStepNumber) {
353 postSimStepOutput();
354 }
355 state = simulationState(stop);
356 #ifdef DEBUG_SIMSTEP
357 std::cout << SIMTIME << " MSNet::simulate(" << start << ", " << stop << ")"
358 << "\n simulation state: " << getStateMessage(state)
359 << std::endl;
360 #endif
361 if (state == SIMSTATE_LOADING) {
362 OptionsIO::setArgs(TraCIServer::getInstance()->getLoadArgs());
363 TraCIServer::getInstance()->getLoadArgs().clear();
364 } else if (state != SIMSTATE_RUNNING) {
365 if (TraCIServer::getInstance() != nullptr && !TraCIServer::wasClosed()) {
366 // overrides SIMSTATE_END_STEP_REACHED, e.g. (TraCI ignore SUMO's --end option)
367 state = SIMSTATE_RUNNING;
368 }
369 }
370 }
371 // report the end when wished
372 WRITE_MESSAGE("Simulation ended at time: " + time2string(getCurrentTimeStep()));
373 WRITE_MESSAGE("Reason: " + getStateMessage(state));
374 // exit simulation loop
375 closeSimulation(start);
376 return state;
377 }
378
379
380 void
loadRoutes()381 MSNet::loadRoutes() {
382 myRouteLoaders->loadNext(myStep);
383 }
384
385
386 const std::string
generateStatistics(SUMOTime start)387 MSNet::generateStatistics(SUMOTime start) {
388 long duration = SysUtils::getCurrentMillis() - mySimBeginMillis;
389 std::ostringstream msg;
390 // print performance notice
391 msg << "Performance: " << "\n" << " Duration: " << duration << "ms" << "\n";
392 if (duration != 0) {
393 msg << " Real time factor: " << (STEPS2TIME(myStep - start) * 1000. / (double)duration) << "\n";
394 msg.setf(std::ios::fixed, std::ios::floatfield); // use decimal format
395 msg.setf(std::ios::showpoint); // print decimal point
396 msg << " UPS: " << ((double)myVehiclesMoved / ((double)duration / 1000)) << "\n";
397 }
398 // print vehicle statistics
399 const std::string discardNotice = ((myVehicleControl->getLoadedVehicleNo() != myVehicleControl->getDepartedVehicleNo()) ?
400 " (Loaded: " + toString(myVehicleControl->getLoadedVehicleNo()) + ")" : "");
401 msg << "Vehicles: " << "\n"
402 << " Inserted: " << myVehicleControl->getDepartedVehicleNo() << discardNotice << "\n"
403 << " Running: " << myVehicleControl->getRunningVehicleNo() << "\n"
404 << " Waiting: " << myInserter->getWaitingVehicleNo() << "\n";
405
406 if (myVehicleControl->getTeleportCount() > 0 || myVehicleControl->getCollisionCount() > 0) {
407 // print optional teleport statistics
408 std::vector<std::string> reasons;
409 if (myVehicleControl->getCollisionCount() > 0) {
410 reasons.push_back("Collisions: " + toString(myVehicleControl->getCollisionCount()));
411 }
412 if (myVehicleControl->getTeleportsJam() > 0) {
413 reasons.push_back("Jam: " + toString(myVehicleControl->getTeleportsJam()));
414 }
415 if (myVehicleControl->getTeleportsYield() > 0) {
416 reasons.push_back("Yield: " + toString(myVehicleControl->getTeleportsYield()));
417 }
418 if (myVehicleControl->getTeleportsWrongLane() > 0) {
419 reasons.push_back("Wrong Lane: " + toString(myVehicleControl->getTeleportsWrongLane()));
420 }
421 msg << "Teleports: " << myVehicleControl->getTeleportCount() << " (" << joinToString(reasons, ", ") << ")\n";
422 }
423 if (myVehicleControl->getEmergencyStops() > 0) {
424 msg << "Emergency Stops: " << myVehicleControl->getEmergencyStops() << "\n";
425 }
426 if (myPersonControl != nullptr && myPersonControl->getLoadedNumber() > 0) {
427 msg << "Persons: " << "\n"
428 << " Inserted: " << myPersonControl->getLoadedNumber() << "\n"
429 << " Running: " << myPersonControl->getRunningNumber() << "\n";
430 if (myPersonControl->getJammedNumber() > 0) {
431 msg << " Jammed: " << myPersonControl->getJammedNumber() << "\n";
432 }
433 }
434 if (OptionsCont::getOptions().getBool("duration-log.statistics")) {
435 msg << MSDevice_Tripinfo::printStatistics();
436 }
437 return msg.str();
438 }
439
440
441 void
closeSimulation(SUMOTime start)442 MSNet::closeSimulation(SUMOTime start) {
443 myDetectorControl->close(myStep);
444 if (OptionsCont::getOptions().getBool("vehroute-output.write-unfinished")) {
445 MSDevice_Vehroutes::generateOutputForUnfinished();
446 }
447 if (OptionsCont::getOptions().getBool("tripinfo-output.write-unfinished")) {
448 MSDevice_Tripinfo::generateOutputForUnfinished();
449 }
450 if (OptionsCont::getOptions().isSet("chargingstations-output")) {
451 writeChargingStationOutput();
452 }
453 if (myLogExecutionTime) {
454 WRITE_MESSAGE(generateStatistics(start));
455 }
456 }
457
458
459 void
simulationStep()460 MSNet::simulationStep() {
461 #ifdef DEBUG_SIMSTEP
462 std::cout << SIMTIME << ": MSNet::simulationStep() called"
463 << ", myStep = " << myStep
464 << std::endl;
465 #endif
466 if (myLogExecutionTime) {
467 myTraCIStepDuration = SysUtils::getCurrentMillis();
468 }
469 TraCIServer* t = TraCIServer::getInstance();
470 if (t != nullptr && !t->isEmbedded()) {
471 t->processCommandsUntilSimStep(myStep);
472 #ifdef DEBUG_SIMSTEP
473 bool loadRequested = !TraCI::getLoadArgs().empty();
474 bool closed = TraCIServer::wasClosed();
475 assert(t->getTargetTime() >= myStep || loadRequested || closed);
476 #endif
477 }
478 if (myLogExecutionTime) {
479 myTraCIStepDuration = SysUtils::getCurrentMillis() - myTraCIStepDuration;
480 }
481 #ifdef DEBUG_SIMSTEP
482 std::cout << SIMTIME << ": TraCI target time: " << t->getTargetTime() << std::endl;
483 #endif
484 // execute beginOfTimestepEvents
485 if (myLogExecutionTime) {
486 mySimStepDuration = SysUtils::getCurrentMillis();
487 }
488 // simulation state output
489 std::vector<SUMOTime>::iterator timeIt = std::find(myStateDumpTimes.begin(), myStateDumpTimes.end(), myStep);
490 if (timeIt != myStateDumpTimes.end()) {
491 const int dist = (int)distance(myStateDumpTimes.begin(), timeIt);
492 MSStateHandler::saveState(myStateDumpFiles[dist], myStep);
493 }
494 if (myStateDumpPeriod > 0 && myStep % myStateDumpPeriod == 0) {
495 MSStateHandler::saveState(myStateDumpPrefix + "_" + time2string(myStep) + myStateDumpSuffix, myStep);
496 }
497 myBeginOfTimestepEvents->execute(myStep);
498 #ifdef HAVE_FOX
499 MSRoutingEngine::waitForAll();
500 #endif
501 if (MSGlobals::gCheck4Accidents) {
502 myEdges->detectCollisions(myStep, STAGE_EVENTS);
503 }
504 // check whether the tls programs need to be switched
505 myLogics->check2Switch(myStep);
506
507 if (MSGlobals::gUseMesoSim) {
508 MSGlobals::gMesoNet->simulate(myStep);
509 myVehicleControl->removePending();
510 } else {
511 // assure all lanes with vehicles are 'active'
512 myEdges->patchActiveLanes();
513
514 // compute safe velocities for all vehicles for the next few lanes
515 // also register ApproachingVehicleInformation for all links
516 myEdges->planMovements(myStep);
517
518 // register junction approaches based on planned velocities as basis for right-of-way decision
519 myEdges->setJunctionApproaches(myStep);
520
521 // decide right-of-way and execute movements
522 myEdges->executeMovements(myStep);
523 if (MSGlobals::gCheck4Accidents) {
524 myEdges->detectCollisions(myStep, STAGE_MOVEMENTS);
525 }
526
527 // vehicles may change lanes
528 myEdges->changeLanes(myStep);
529
530 if (MSGlobals::gCheck4Accidents) {
531 myEdges->detectCollisions(myStep, STAGE_LANECHANGE);
532 }
533 }
534 loadRoutes();
535
536 // persons
537 if (myPersonControl != nullptr && myPersonControl->hasTransportables()) {
538 myPersonControl->checkWaiting(this, myStep);
539 }
540 // containers
541 if (myContainerControl != nullptr && myContainerControl->hasTransportables()) {
542 myContainerControl->checkWaiting(this, myStep);
543 }
544 // insert vehicles
545 myInserter->determineCandidates(myStep);
546 myInsertionEvents->execute(myStep);
547 #ifdef HAVE_FOX
548 MSRoutingEngine::waitForAll();
549 #endif
550 myInserter->emitVehicles(myStep);
551 if (MSGlobals::gCheck4Accidents) {
552 //myEdges->patchActiveLanes(); // @note required to detect collisions on lanes that were empty before insertion. wasteful?
553 myEdges->detectCollisions(myStep, STAGE_INSERTIONS);
554 }
555 MSVehicleTransfer::getInstance()->checkInsertions(myStep);
556
557 // execute endOfTimestepEvents
558 myEndOfTimestepEvents->execute(myStep);
559
560 if (myLogExecutionTime) {
561 myTraCIStepDuration -= SysUtils::getCurrentMillis();
562 }
563 libsumo::Helper::postProcessRemoteControl();
564 if (myLogExecutionTime) {
565 myTraCIStepDuration += SysUtils::getCurrentMillis();
566 }
567 // update and write (if needed) detector values
568 writeOutput();
569
570 if (myLogExecutionTime) {
571 mySimStepDuration = SysUtils::getCurrentMillis() - mySimStepDuration;
572 myVehiclesMoved += myVehicleControl->getRunningVehicleNo();
573 }
574 myStep += DELTA_T;
575 }
576
577
578 MSNet::SimulationState
simulationState(SUMOTime stopTime) const579 MSNet::simulationState(SUMOTime stopTime) const {
580 if (TraCIServer::wasClosed()) {
581 return SIMSTATE_CONNECTION_CLOSED;
582 }
583 if (TraCIServer::getInstance() != nullptr && !TraCIServer::getInstance()->getLoadArgs().empty()) {
584 return SIMSTATE_LOADING;
585 }
586 if ((stopTime < 0 || myStep > stopTime) && TraCIServer::getInstance() == nullptr && (stopTime > 0 || myStep > myEdgeDataEndTime)) {
587 if ((myVehicleControl->getActiveVehicleCount() == 0)
588 && (myInserter->getPendingFlowCount() == 0)
589 && (myPersonControl == nullptr || !myPersonControl->hasNonWaiting())
590 && (myContainerControl == nullptr || !myContainerControl->hasNonWaiting())) {
591 if (myPersonControl) {
592 myPersonControl->abortWaitingForVehicle();
593 }
594 if (myContainerControl) {
595 myContainerControl->abortWaitingForVehicle();
596 }
597 myVehicleControl->abortWaiting();
598 return SIMSTATE_NO_FURTHER_VEHICLES;
599 }
600 }
601 if (stopTime >= 0 && myStep >= stopTime) {
602 return SIMSTATE_END_STEP_REACHED;
603 }
604 if (myMaxTeleports >= 0 && myVehicleControl->getTeleportCount() > myMaxTeleports) {
605 return SIMSTATE_TOO_MANY_TELEPORTS;
606 }
607 if (myAmInterrupted) {
608 return SIMSTATE_INTERRUPTED;
609 }
610 return SIMSTATE_RUNNING;
611 }
612
613
614 std::string
getStateMessage(MSNet::SimulationState state)615 MSNet::getStateMessage(MSNet::SimulationState state) {
616 switch (state) {
617 case MSNet::SIMSTATE_RUNNING:
618 return "";
619 case MSNet::SIMSTATE_END_STEP_REACHED:
620 return "The final simulation step has been reached.";
621 case MSNet::SIMSTATE_NO_FURTHER_VEHICLES:
622 return "All vehicles have left the simulation.";
623 case MSNet::SIMSTATE_CONNECTION_CLOSED:
624 return "TraCI requested termination.";
625 case MSNet::SIMSTATE_ERROR_IN_SIM:
626 return "An error occurred (see log).";
627 case MSNet::SIMSTATE_INTERRUPTED:
628 return "Interrupted.";
629 case MSNet::SIMSTATE_TOO_MANY_TELEPORTS:
630 return "Too many teleports.";
631 case MSNet::SIMSTATE_LOADING:
632 return "TraCI issued load command.";
633 default:
634 return "Unknown reason.";
635 }
636 }
637
638
639 void
clearAll()640 MSNet::clearAll() {
641 // clear container
642 MSEdge::clear();
643 MSLane::clear();
644 MSRoute::clear();
645 delete MSVehicleTransfer::getInstance();
646 MSDevice::cleanupAll();
647 MSTrigger::cleanup();
648 MSCalibrator::cleanup();
649 MSPModel::cleanup();
650 MSCModel_NonInteracting::cleanup();
651 MSDevice_BTsender::cleanup();
652 MSDevice_SSM::cleanup();
653 MSDevice_ToC::cleanup();
654 MSStopOut::cleanup();
655 TraCIServer* t = TraCIServer::getInstance();
656 if (t != nullptr) {
657 t->cleanup();
658 }
659 libsumo::Helper::cleanup();
660 OutputDevice::closeAll(true);
661 }
662
663
664 void
writeOutput()665 MSNet::writeOutput() {
666 // update detector values
667 myDetectorControl->updateDetectors(myStep);
668 const OptionsCont& oc = OptionsCont::getOptions();
669
670 // check state dumps
671 if (oc.isSet("netstate-dump")) {
672 MSXMLRawOut::write(OutputDevice::getDeviceByOption("netstate-dump"), *myEdges, myStep,
673 oc.getInt("netstate-dump.precision"));
674 }
675
676 // check fcd dumps
677 if (OptionsCont::getOptions().isSet("fcd-output")) {
678 MSFCDExport::write(OutputDevice::getDeviceByOption("fcd-output"), myStep, myHasElevation);
679 }
680
681 // check emission dumps
682 if (OptionsCont::getOptions().isSet("emission-output")) {
683 MSEmissionExport::write(OutputDevice::getDeviceByOption("emission-output"), myStep,
684 oc.getInt("emission-output.precision"));
685 }
686
687 // battery dumps
688 if (OptionsCont::getOptions().isSet("battery-output")) {
689 MSBatteryExport::write(OutputDevice::getDeviceByOption("battery-output"), myStep,
690 oc.getInt("battery-output.precision"));
691 }
692
693 // check full dumps
694 if (OptionsCont::getOptions().isSet("full-output")) {
695 MSFullExport::write(OutputDevice::getDeviceByOption("full-output"), myStep);
696 }
697
698 // check queue dumps
699 if (OptionsCont::getOptions().isSet("queue-output")) {
700 MSQueueExport::write(OutputDevice::getDeviceByOption("queue-output"), myStep);
701 }
702
703 // check amitran dumps
704 if (OptionsCont::getOptions().isSet("amitran-output")) {
705 MSAmitranTrajectories::write(OutputDevice::getDeviceByOption("amitran-output"), myStep);
706 }
707
708 // check vtk dumps
709 if (OptionsCont::getOptions().isSet("vtk-output")) {
710
711 if (MSNet::getInstance()->getVehicleControl().getRunningVehicleNo() > 0) {
712 std::string timestep = time2string(myStep);
713 timestep = timestep.substr(0, timestep.length() - 3);
714 std::string output = OptionsCont::getOptions().getString("vtk-output");
715 std::string filename = output + "_" + timestep + ".vtp";
716
717 OutputDevice_File dev = OutputDevice_File(filename, false);
718
719 //build a huge mass of xml files
720 MSVTKExport::write(dev, myStep);
721
722 }
723
724 }
725
726 // summary output
727 if (OptionsCont::getOptions().isSet("summary-output")) {
728 OutputDevice& od = OutputDevice::getDeviceByOption("summary-output");
729 int departedVehiclesNumber = myVehicleControl->getDepartedVehicleNo();
730 const double meanWaitingTime = departedVehiclesNumber != 0 ? myVehicleControl->getTotalDepartureDelay() / (double) departedVehiclesNumber : -1.;
731 int endedVehicleNumber = myVehicleControl->getEndedVehicleNo();
732 const double meanTravelTime = endedVehicleNumber != 0 ? myVehicleControl->getTotalTravelTime() / (double) endedVehicleNumber : -1.;
733 od.openTag("step");
734 od.writeAttr("time", time2string(myStep));
735 od.writeAttr("loaded", myVehicleControl->getLoadedVehicleNo());
736 od.writeAttr("inserted", myVehicleControl->getDepartedVehicleNo());
737 od.writeAttr("running", myVehicleControl->getRunningVehicleNo());
738 od.writeAttr("waiting", myInserter->getWaitingVehicleNo());
739 od.writeAttr("ended", myVehicleControl->getEndedVehicleNo());
740 od.writeAttr("arrived", myVehicleControl->getArrivedVehicleNo());
741 od.writeAttr("collisions", myVehicleControl->getCollisionCount());
742 od.writeAttr("teleports", myVehicleControl->getTeleportCount());
743 od.writeAttr("halting", myVehicleControl->getHaltingVehicleNo());
744 od.writeAttr("meanWaitingTime", meanWaitingTime);
745 od.writeAttr("meanTravelTime", meanTravelTime);
746 std::pair<double, double> meanSpeed = myVehicleControl->getVehicleMeanSpeeds();
747 od.writeAttr("meanSpeed", meanSpeed.first);
748 od.writeAttr("meanSpeedRelative", meanSpeed.second);
749 if (myLogExecutionTime) {
750 od.writeAttr("duration", mySimStepDuration);
751 }
752 od.closeTag();
753 }
754
755 // write detector values
756 myDetectorControl->writeOutput(myStep + DELTA_T, false);
757
758 // write link states
759 if (OptionsCont::getOptions().isSet("link-output")) {
760 OutputDevice& od = OutputDevice::getDeviceByOption("link-output");
761 od.openTag("timestep");
762 od.writeAttr(SUMO_ATTR_ID, STEPS2TIME(myStep));
763 const MSEdgeVector& edges = myEdges->getEdges();
764 for (MSEdgeVector::const_iterator i = edges.begin(); i != edges.end(); ++i) {
765 const std::vector<MSLane*>& lanes = (*i)->getLanes();
766 for (std::vector<MSLane*>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
767 const std::vector<MSLink*>& links = (*j)->getLinkCont();
768 for (std::vector<MSLink*>::const_iterator k = links.begin(); k != links.end(); ++k) {
769 (*k)->writeApproaching(od, (*j)->getID());
770 }
771 }
772 }
773 od.closeTag();
774 }
775
776 // write SSM output
777 for (std::set<MSDevice_SSM*>::iterator di = MSDevice_SSM::getInstances().begin(); di != MSDevice_SSM::getInstances().end(); ++di) {
778 MSDevice_SSM* dev = (*di);
779 dev->updateAndWriteOutput();
780 }
781
782 // write ToC output
783 for (std::set<MSDevice_ToC*>::iterator di = MSDevice_ToC::getInstances().begin(); di != MSDevice_ToC::getInstances().end(); ++di) {
784 MSDevice_ToC* dev = (*di);
785 if (dev->generatesOutput()) {
786 dev->writeOutput();
787 }
788 }
789 }
790
791
792 bool
logSimulationDuration() const793 MSNet::logSimulationDuration() const {
794 return myLogExecutionTime;
795 }
796
797
798 MSTransportableControl&
getPersonControl()799 MSNet::getPersonControl() {
800 if (myPersonControl == nullptr) {
801 myPersonControl = new MSTransportableControl();
802 }
803 return *myPersonControl;
804 }
805
806 MSTransportableControl&
getContainerControl()807 MSNet::getContainerControl() {
808 if (myContainerControl == nullptr) {
809 myContainerControl = new MSTransportableControl();
810 }
811 return *myContainerControl;
812 }
813
814 MSDynamicShapeUpdater*
makeDynamicShapeUpdater()815 MSNet::makeDynamicShapeUpdater() {
816 myDynamicShapeUpdater = std::unique_ptr<MSDynamicShapeUpdater> (new MSDynamicShapeUpdater(MSNet::getInstance()->getShapeContainer()));
817 return myDynamicShapeUpdater.get();
818 }
819
820 MSEdgeWeightsStorage&
getWeightsStorage()821 MSNet::getWeightsStorage() {
822 if (myEdgeWeights == nullptr) {
823 myEdgeWeights = new MSEdgeWeightsStorage();
824 }
825 return *myEdgeWeights;
826 }
827
828
829 void
preSimStepOutput() const830 MSNet::preSimStepOutput() const {
831 std::cout << "Step #" << time2string(myStep);
832 }
833
834
835 void
postSimStepOutput() const836 MSNet::postSimStepOutput() const {
837 if (myLogExecutionTime) {
838 std::ostringstream oss;
839 oss.setf(std::ios::fixed, std::ios::floatfield); // use decimal format
840 oss.setf(std::ios::showpoint); // print decimal point
841 oss << std::setprecision(gPrecision);
842 if (mySimStepDuration != 0) {
843 const double durationSec = (double)mySimStepDuration / 1000.;
844 oss << " (" << mySimStepDuration << "ms ~= "
845 << (TS / durationSec) << "*RT, ~"
846 << ((double) myVehicleControl->getRunningVehicleNo() / durationSec);
847 } else {
848 oss << " (0ms ?*RT. ?";
849 }
850 oss << "UPS, ";
851 if (TraCIServer::getInstance() != nullptr) {
852 oss << "TraCI: " << myTraCIStepDuration << "ms, ";
853 }
854 oss << "vehicles TOT " << myVehicleControl->getDepartedVehicleNo()
855 << " ACT " << myVehicleControl->getRunningVehicleNo()
856 << " BUF " << myInserter->getWaitingVehicleNo()
857 << ") ";
858 std::string prev = "Step #" + time2string(myStep - DELTA_T);
859 std::cout << oss.str().substr(0, 90 - prev.length());
860 }
861 std::cout << '\r';
862 }
863
864
865 void
addVehicleStateListener(VehicleStateListener * listener)866 MSNet::addVehicleStateListener(VehicleStateListener* listener) {
867 if (find(myVehicleStateListeners.begin(), myVehicleStateListeners.end(), listener) == myVehicleStateListeners.end()) {
868 myVehicleStateListeners.push_back(listener);
869 }
870 }
871
872
873 void
removeVehicleStateListener(VehicleStateListener * listener)874 MSNet::removeVehicleStateListener(VehicleStateListener* listener) {
875 std::vector<VehicleStateListener*>::iterator i = std::find(myVehicleStateListeners.begin(), myVehicleStateListeners.end(), listener);
876 if (i != myVehicleStateListeners.end()) {
877 myVehicleStateListeners.erase(i);
878 }
879 }
880
881
882 void
informVehicleStateListener(const SUMOVehicle * const vehicle,VehicleState to,const std::string & info)883 MSNet::informVehicleStateListener(const SUMOVehicle* const vehicle, VehicleState to, const std::string& info) {
884 for (std::vector<VehicleStateListener*>::iterator i = myVehicleStateListeners.begin(); i != myVehicleStateListeners.end(); ++i) {
885 (*i)->vehicleStateChanged(vehicle, to, info);
886 }
887 }
888
889
890 bool
addStoppingPlace(const SumoXMLTag category,MSStoppingPlace * stop)891 MSNet::addStoppingPlace(const SumoXMLTag category, MSStoppingPlace* stop) {
892 return myStoppingPlaces[category == SUMO_TAG_TRAIN_STOP ? SUMO_TAG_BUS_STOP : category].add(stop->getID(), stop);
893 }
894
895
896 MSStoppingPlace*
getStoppingPlace(const std::string & id,const SumoXMLTag category) const897 MSNet::getStoppingPlace(const std::string& id, const SumoXMLTag category) const {
898 if (myStoppingPlaces.count(category) > 0) {
899 return myStoppingPlaces.find(category)->second.get(id);
900 }
901 return nullptr;
902 }
903
904
905 std::string
getStoppingPlaceID(const MSLane * lane,const double pos,const SumoXMLTag category) const906 MSNet::getStoppingPlaceID(const MSLane* lane, const double pos, const SumoXMLTag category) const {
907 if (myStoppingPlaces.count(category) > 0) {
908 for (const auto& it : myStoppingPlaces.find(category)->second) {
909 MSStoppingPlace* stop = it.second;
910 if (&stop->getLane() == lane && stop->getBeginLanePosition() - POSITION_EPS <= pos && stop->getEndLanePosition() + POSITION_EPS >= pos) {
911 return stop->getID();
912 }
913 }
914 }
915 return "";
916 }
917
918
919 const NamedObjectCont<MSStoppingPlace*>&
getStoppingPlaces(SumoXMLTag category) const920 MSNet::getStoppingPlaces(SumoXMLTag category) const {
921 auto it = myStoppingPlaces.find(category);
922 if (it != myStoppingPlaces.end()) {
923 return it->second;
924 } else {
925 throw ProcessError("No stoppingPlace of type '" + toString(category) + "' found");
926 }
927 }
928
929 void
writeChargingStationOutput() const930 MSNet::writeChargingStationOutput() const {
931 if (myStoppingPlaces.count(SUMO_TAG_CHARGING_STATION) > 0) {
932 OutputDevice& output = OutputDevice::getDeviceByOption("chargingstations-output");
933 for (const auto& it : myStoppingPlaces.find(SUMO_TAG_CHARGING_STATION)->second) {
934 static_cast<MSChargingStation*>(it.second)->writeChargingStationOutput(output);
935 }
936 }
937 }
938
939
940 SUMOAbstractRouter<MSEdge, SUMOVehicle>&
getRouterTT(const MSEdgeVector & prohibited) const941 MSNet::getRouterTT(const MSEdgeVector& prohibited) const {
942 if (myRouterTT == nullptr) {
943 const std::string routingAlgorithm = OptionsCont::getOptions().getString("routing-algorithm");
944 if (routingAlgorithm == "dijkstra") {
945 myRouterTT = new DijkstraRouter<MSEdge, SUMOVehicle, SUMOAbstractRouterPermissions<MSEdge, SUMOVehicle> >(
946 MSEdge::getAllEdges(), true, &MSNet::getTravelTime);
947 } else {
948 if (routingAlgorithm != "astar") {
949 WRITE_WARNING("TraCI and Triggers cannot use routing algorithm '" + routingAlgorithm + "'. using 'astar' instead.");
950 }
951 myRouterTT = new AStarRouter<MSEdge, SUMOVehicle, SUMOAbstractRouterPermissions<MSEdge, SUMOVehicle> >(
952 MSEdge::getAllEdges(), true, &MSNet::getTravelTime);
953 }
954 }
955 dynamic_cast<SUMOAbstractRouterPermissions<MSEdge, SUMOVehicle>*>(myRouterTT)->prohibit(prohibited);
956 return *myRouterTT;
957 }
958
959
960 SUMOAbstractRouter<MSEdge, SUMOVehicle>&
getRouterEffort(const MSEdgeVector & prohibited) const961 MSNet::getRouterEffort(const MSEdgeVector& prohibited) const {
962 if (myRouterEffort == nullptr) {
963 myRouterEffort = new DijkstraRouter<MSEdge, SUMOVehicle, SUMOAbstractRouterPermissions<MSEdge, SUMOVehicle> >(
964 MSEdge::getAllEdges(), true, &MSNet::getEffort, &MSNet::getTravelTime);
965 }
966 dynamic_cast<SUMOAbstractRouterPermissions<MSEdge, SUMOVehicle>*>(myRouterEffort)->prohibit(prohibited);
967 return *myRouterEffort;
968 }
969
970
971 MSNet::MSPedestrianRouter&
getPedestrianRouter(const MSEdgeVector & prohibited) const972 MSNet::getPedestrianRouter(const MSEdgeVector& prohibited) const {
973 if (myPedestrianRouter == nullptr) {
974 myPedestrianRouter = new MSPedestrianRouter();
975 }
976 myPedestrianRouter->prohibit(prohibited);
977 return *myPedestrianRouter;
978 }
979
980
981 MSNet::MSIntermodalRouter&
getIntermodalRouter(const int routingMode,const MSEdgeVector & prohibited) const982 MSNet::getIntermodalRouter(const int routingMode, const MSEdgeVector& prohibited) const {
983 if (myIntermodalRouter.count(routingMode) == 0) {
984 int carWalk = 0;
985 for (const std::string& opt : OptionsCont::getOptions().getStringVector("persontrip.transfer.car-walk")) {
986 if (opt == "parkingAreas") {
987 carWalk |= MSIntermodalRouter::Network::PARKING_AREAS;
988 } else if (opt == "ptStops") {
989 carWalk |= MSIntermodalRouter::Network::PT_STOPS;
990 } else if (opt == "allJunctions") {
991 carWalk |= MSIntermodalRouter::Network::ALL_JUNCTIONS;
992 }
993 }
994 const std::string routingAlgorithm = OptionsCont::getOptions().getString("routing-algorithm");
995 if (routingMode == libsumo::ROUTING_MODE_COMBINED) {
996 myIntermodalRouter[routingMode] = new MSIntermodalRouter(MSNet::adaptIntermodalRouter, carWalk, routingAlgorithm, routingMode, new FareModul());
997 } else {
998 myIntermodalRouter[routingMode] = new MSIntermodalRouter(MSNet::adaptIntermodalRouter, carWalk, routingAlgorithm, routingMode);
999 }
1000 }
1001 myIntermodalRouter[routingMode]->prohibit(prohibited);
1002 return *myIntermodalRouter[routingMode];
1003 }
1004
1005
1006 void
adaptIntermodalRouter(MSIntermodalRouter & router)1007 MSNet::adaptIntermodalRouter(MSIntermodalRouter& router) {
1008 // add access to all parking areas
1009 for (const auto& i : myInstance->myStoppingPlaces[SUMO_TAG_PARKING_AREA]) {
1010 const MSEdge* const edge = &i.second->getLane().getEdge();
1011 router.getNetwork()->addAccess(i.first, edge, i.second->getAccessPos(edge), i.second->getAccessDistance(edge), SUMO_TAG_PARKING_AREA);
1012 }
1013 EffortCalculator* const external = router.getExternalEffort();
1014 // add access to all public transport stops
1015 for (const auto& i : myInstance->myStoppingPlaces[SUMO_TAG_BUS_STOP]) {
1016 const MSEdge* const edge = &i.second->getLane().getEdge();
1017 router.getNetwork()->addAccess(i.first, edge, i.second->getAccessPos(edge),
1018 i.second->getAccessDistance(edge), SUMO_TAG_BUS_STOP);
1019 for (const auto& a : i.second->getAllAccessPos()) {
1020 router.getNetwork()->addAccess(i.first, &std::get<0>(a)->getEdge(), std::get<1>(a), std::get<2>(a), SUMO_TAG_BUS_STOP);
1021 }
1022 if (external != nullptr) {
1023 external->addStop(router.getNetwork()->getStopEdge(i.first)->getNumericalID(), *i.second);
1024 }
1025 }
1026 myInstance->getInsertionControl().adaptIntermodalRouter(router);
1027 myInstance->getVehicleControl().adaptIntermodalRouter(router);
1028 }
1029
1030
1031 bool
checkElevation()1032 MSNet::checkElevation() {
1033 const MSEdgeVector& edges = myEdges->getEdges();
1034 for (MSEdgeVector::const_iterator e = edges.begin(); e != edges.end(); ++e) {
1035 for (std::vector<MSLane*>::const_iterator i = (*e)->getLanes().begin(); i != (*e)->getLanes().end(); ++i) {
1036 if ((*i)->getShape().hasElevation()) {
1037 return true;
1038 }
1039 }
1040 }
1041 return false;
1042 }
1043
1044
1045 bool
checkWalkingarea()1046 MSNet::checkWalkingarea() {
1047 for (const MSEdge* e : myEdges->getEdges()) {
1048 if (e->getFunction() == EDGEFUNC_WALKINGAREA) {
1049 return true;
1050 }
1051 }
1052 return false;
1053 }
1054
1055
1056 bool
warnOnce(const std::string & typeAndID)1057 MSNet::warnOnce(const std::string& typeAndID) {
1058 if (myWarnedOnce.find(typeAndID) == myWarnedOnce.end()) {
1059 myWarnedOnce[typeAndID] = true;
1060 return true;
1061 }
1062 return false;
1063 }
1064
1065
1066 /****************************************************************************/
1067