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