LCOV - code coverage report
Current view: top level - src/microsim - MSNet.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 95.6 % 931 890
Test Date: 2026-03-26 16:31:35 Functions: 95.8 % 71 68

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 German Aerospace Center (DLR) and others.
       4              : // This program and the accompanying materials are made available under the
       5              : // terms of the Eclipse Public License 2.0 which is available at
       6              : // https://www.eclipse.org/legal/epl-2.0/
       7              : // This Source Code may also be made available under the following Secondary
       8              : // Licenses when the conditions for such availability set forth in the Eclipse
       9              : // Public License 2.0 are satisfied: GNU General Public License, version 2
      10              : // or later which is available at
      11              : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
      12              : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
      13              : /****************************************************************************/
      14              : /// @file    MSNet.cpp
      15              : /// @author  Christian Roessel
      16              : /// @author  Daniel Krajzewicz
      17              : /// @author  Jakob Erdmann
      18              : /// @author  Clemens Honomichl
      19              : /// @author  Eric Nicolay
      20              : /// @author  Mario Krumnow
      21              : /// @author  Michael Behrisch
      22              : /// @author  Christoph Sommer
      23              : /// @date    Tue, 06 Mar 2001
      24              : ///
      25              : // The simulated network and simulation performer
      26              : /****************************************************************************/
      27              : #include <config.h>
      28              : 
      29              : #ifdef HAVE_VERSION_H
      30              : #include <version.h>
      31              : #endif
      32              : 
      33              : #include <string>
      34              : #include <iostream>
      35              : #include <sstream>
      36              : #include <typeinfo>
      37              : #include <algorithm>
      38              : #include <cassert>
      39              : #include <vector>
      40              : #include <ctime>
      41              : 
      42              : #ifdef HAVE_FOX
      43              : #include <utils/common/ScopedLocker.h>
      44              : #endif
      45              : #include <utils/common/MsgHandler.h>
      46              : #include <utils/common/ToString.h>
      47              : #include <utils/common/SysUtils.h>
      48              : #include <utils/common/UtilExceptions.h>
      49              : #include <utils/common/WrappingCommand.h>
      50              : #include <utils/common/SystemFrame.h>
      51              : #include <utils/geom/GeoConvHelper.h>
      52              : #include <utils/iodevices/OutputDevice_File.h>
      53              : #include <utils/iodevices/OutputDevice.h>
      54              : #include <utils/options/OptionsCont.h>
      55              : #include <utils/options/OptionsIO.h>
      56              : #include <utils/shapes/ShapeContainer.h>
      57              : #include <utils/router/DijkstraRouter.h>
      58              : #include <utils/router/AStarRouter.h>
      59              : #include <utils/router/IntermodalRouter.h>
      60              : #include <utils/router/PedestrianRouter.h>
      61              : #include <utils/vehicle/SUMORouteLoaderControl.h>
      62              : #include <utils/vehicle/SUMORouteLoader.h>
      63              : #include <utils/vehicle/SUMOVehicleParserHelper.h>
      64              : #include <utils/xml/XMLSubSys.h>
      65              : #include <traci-server/TraCIServer.h>
      66              : #include <libsumo/Helper.h>
      67              : #include <libsumo/Simulation.h>
      68              : #include <mesosim/MELoop.h>
      69              : #include <mesosim/MESegment.h>
      70              : #include <microsim/output/MSDetectorControl.h>
      71              : #include <microsim/MSVehicleTransfer.h>
      72              : #include <microsim/devices/MSRoutingEngine.h>
      73              : #include <microsim/devices/MSDevice_Vehroutes.h>
      74              : #include <microsim/devices/MSDevice_Tripinfo.h>
      75              : #include <microsim/devices/MSDevice_BTsender.h>
      76              : #include <microsim/devices/MSDevice_SSM.h>
      77              : #include <microsim/devices/MSDevice_ElecHybrid.h>
      78              : #include <microsim/devices/MSDevice_ToC.h>
      79              : #include <microsim/devices/MSDevice_Taxi.h>
      80              : #include <microsim/output/MSBatteryExport.h>
      81              : #include <microsim/output/MSChargingStationExport.h>
      82              : #include <microsim/output/MSElecHybridExport.h>
      83              : #include <microsim/output/MSEmissionExport.h>
      84              : #include <microsim/output/MSFCDExport.h>
      85              : #include <microsim/output/MSFullExport.h>
      86              : #include <microsim/output/MSQueueExport.h>
      87              : #include <microsim/output/MSVTKExport.h>
      88              : #include <microsim/output/MSXMLRawOut.h>
      89              : #include <microsim/output/MSAmitranTrajectories.h>
      90              : #include <microsim/output/MSStopOut.h>
      91              : #include <microsim/transportables/MSPModel.h>
      92              : #include <microsim/transportables/MSPerson.h>
      93              : #include <microsim/traffic_lights/MSTrafficLightLogic.h>
      94              : #include <microsim/transportables/MSTransportableControl.h>
      95              : #include <microsim/traffic_lights/MSRailSignal.h>
      96              : #include <microsim/traffic_lights/MSRailSignalConstraint.h>
      97              : #include <microsim/traffic_lights/MSRailSignalControl.h>
      98              : #include <microsim/traffic_lights/MSTLLogicControl.h>
      99              : #include <microsim/traffic_lights/MSDriveWay.h>
     100              : #include <microsim/trigger/MSCalibrator.h>
     101              : #include <microsim/trigger/MSChargingStation.h>
     102              : #include <microsim/trigger/MSLaneSpeedTrigger.h>
     103              : #include <microsim/trigger/MSOverheadWire.h>
     104              : #include <microsim/trigger/MSTriggeredRerouter.h>
     105              : #include <utils/router/FareModul.h>
     106              : #include <netload/NLBuilder.h>
     107              : 
     108              : #include "MSEdgeControl.h"
     109              : #include "MSJunctionControl.h"
     110              : #include "MSInsertionControl.h"
     111              : #include "MSDynamicShapeUpdater.h"
     112              : #include "MSEventControl.h"
     113              : #include "MSEdge.h"
     114              : #include "MSJunction.h"
     115              : #include "MSJunctionLogic.h"
     116              : #include "MSLane.h"
     117              : #include "MSVehicleControl.h"
     118              : #include "MSVehicleTransfer.h"
     119              : #include "MSRoute.h"
     120              : #include "MSGlobals.h"
     121              : #include "MSEdgeWeightsStorage.h"
     122              : #include "MSStateHandler.h"
     123              : #include "MSFrame.h"
     124              : #include "MSParkingArea.h"
     125              : #include "MSStoppingPlace.h"
     126              : #include "MSNet.h"
     127              : 
     128              : 
     129              : // ===========================================================================
     130              : // debug constants
     131              : // ===========================================================================
     132              : //#define DEBUG_SIMSTEP
     133              : 
     134              : 
     135              : // ===========================================================================
     136              : // static member definitions
     137              : // ===========================================================================
     138              : MSNet* MSNet::myInstance = nullptr;
     139              : 
     140              : const std::string MSNet::STAGE_EVENTS("events");
     141              : const std::string MSNet::STAGE_MOVEMENTS("move");
     142              : const std::string MSNet::STAGE_LANECHANGE("laneChange");
     143              : const std::string MSNet::STAGE_INSERTIONS("insertion");
     144              : const std::string MSNet::STAGE_REMOTECONTROL("remoteControl");
     145              : 
     146              : const NamedObjectCont<MSStoppingPlace*> MSNet::myEmptyStoppingPlaceCont;
     147              : const std::vector<MSStoppingPlace*> MSNet::myEmptyStoppingPlaceVector;
     148              : 
     149              : // ===========================================================================
     150              : // static member method definitions
     151              : // ===========================================================================
     152              : double
     153          336 : MSNet::getEffort(const MSEdge* const e, const SUMOVehicle* const v, double t) {
     154              :     double value;
     155          336 :     const MSVehicle* const veh = dynamic_cast<const MSVehicle* const>(v);
     156          336 :     if (veh != nullptr && veh->getWeightsStorage().retrieveExistingEffort(e, t, value)) {
     157            2 :         return value;
     158              :     }
     159          334 :     if (getInstance()->getWeightsStorage().retrieveExistingEffort(e, t, value)) {
     160            2 :         return value;
     161              :     }
     162              :     return 0;
     163              : }
     164              : 
     165              : 
     166              : double
     167      6822247 : MSNet::getTravelTime(const MSEdge* const e, const SUMOVehicle* const v, double t) {
     168              :     double value;
     169      6822247 :     const MSVehicle* const veh = dynamic_cast<const MSVehicle* const>(v);
     170      6821415 :     if (veh != nullptr && veh->getWeightsStorage().retrieveExistingTravelTime(e, t, value)) {
     171          522 :         return value;
     172              :     }
     173      6821725 :     if (getInstance()->getWeightsStorage().retrieveExistingTravelTime(e, t, value)) {
     174          177 :         return value;
     175              :     }
     176      6821548 :     if (veh != nullptr && veh->getRoutingMode() == libsumo::ROUTING_MODE_AGGREGATED_CUSTOM) {
     177         2945 :         return MSRoutingEngine::getEffortExtra(e, v, t);
     178              :     }
     179      6818603 :     return e->getMinimumTravelTime(v);
     180              : }
     181              : 
     182              : 
     183              : // ---------------------------------------------------------------------------
     184              : // MSNet - methods
     185              : // ---------------------------------------------------------------------------
     186              : MSNet*
     187   5439469484 : MSNet::getInstance(void) {
     188   5439469484 :     if (myInstance != nullptr) {
     189   5439469439 :         return myInstance;
     190              :     }
     191           90 :     throw ProcessError(TL("A network was not yet constructed."));
     192              : }
     193              : 
     194              : void
     195        41523 : MSNet::initStatic() {
     196        41523 :     gRoutingPreferences = false;
     197        41523 :     MSDriveWay::init();
     198        41523 : }
     199              : 
     200              : void
     201        40903 : MSNet::cleanupStatic() {
     202        40903 :     if (!MSGlobals::gUseMesoSim) {
     203        34657 :         MSVehicle::Influencer::cleanup();
     204              :     }
     205        40903 : }
     206              : 
     207              : 
     208        41523 : MSNet::MSNet(MSVehicleControl* vc, MSEventControl* beginOfTimestepEvents,
     209              :              MSEventControl* endOfTimestepEvents,
     210              :              MSEventControl* insertionEvents,
     211        41523 :              ShapeContainer* shapeCont):
     212        41523 :     myAmInterrupted(false),
     213        41523 :     myVehiclesMoved(0),
     214        41523 :     myPersonsMoved(0),
     215        41523 :     myHavePermissions(false),
     216        41523 :     myHasInternalLinks(false),
     217        41523 :     myJunctionHigherSpeeds(false),
     218        41523 :     myHasElevation(false),
     219        41523 :     myHasPedestrianNetwork(false),
     220        41523 :     myHasBidiEdges(false),
     221        41523 :     myEdgeDataEndTime(-1),
     222        41523 :     myDynamicShapeUpdater(nullptr) {
     223        41523 :     if (myInstance != nullptr) {
     224            0 :         throw ProcessError(TL("A network was already constructed."));
     225              :     }
     226        41523 :     OptionsCont& oc = OptionsCont::getOptions();
     227        41523 :     myStep = string2time(oc.getString("begin"));
     228        41523 :     myMaxTeleports = oc.getInt("max-num-teleports");
     229        41523 :     myLogExecutionTime = !oc.getBool("no-duration-log");
     230        41523 :     myLogStepNumber = !oc.getBool("no-step-log");
     231        41523 :     myLogStepPeriod = oc.getInt("step-log.period");
     232       166092 :     myInserter = new MSInsertionControl(*vc, string2time(oc.getString("max-depart-delay")), oc.getBool("eager-insert"), oc.getInt("max-num-vehicles"),
     233       166092 :                                         string2time(oc.getString("random-depart-offset")));
     234        41523 :     myVehicleControl = vc;
     235        41523 :     myDetectorControl = new MSDetectorControl();
     236        41523 :     myEdges = nullptr;
     237        41523 :     myJunctions = nullptr;
     238        41523 :     myRouteLoaders = nullptr;
     239        41523 :     myLogics = nullptr;
     240        41523 :     myPersonControl = nullptr;
     241        41523 :     myContainerControl = nullptr;
     242        41523 :     myEdgeWeights = nullptr;
     243        41523 :     myShapeContainer = shapeCont == nullptr ? new ShapeContainer() : shapeCont;
     244              : 
     245        41523 :     myBeginOfTimestepEvents = beginOfTimestepEvents;
     246        41523 :     myEndOfTimestepEvents = endOfTimestepEvents;
     247        41523 :     myInsertionEvents = insertionEvents;
     248        41523 :     myLanesRTree.first = false;
     249              : 
     250        41523 :     if (MSGlobals::gUseMesoSim) {
     251        12700 :         MSGlobals::gMesoNet = new MELoop(string2time(oc.getString("meso-recheck")));
     252              :     }
     253        41523 :     myInstance = this;
     254        41523 :     initStatic();
     255        41523 : }
     256              : 
     257              : 
     258              : void
     259        41045 : MSNet::closeBuilding(const OptionsCont& oc, MSEdgeControl* edges, MSJunctionControl* junctions,
     260              :                      SUMORouteLoaderControl* routeLoaders,
     261              :                      MSTLLogicControl* tlc,
     262              :                      std::vector<SUMOTime> stateDumpTimes,
     263              :                      std::vector<std::string> stateDumpFiles,
     264              :                      bool hasInternalLinks,
     265              :                      bool junctionHigherSpeeds,
     266              :                      const MMVersion& version) {
     267        41045 :     myEdges = edges;
     268        41045 :     myJunctions = junctions;
     269        41045 :     myRouteLoaders = routeLoaders;
     270        41045 :     myLogics = tlc;
     271              :     // save the time the network state shall be saved at
     272        41045 :     myStateDumpTimes = stateDumpTimes;
     273        41045 :     myStateDumpFiles = stateDumpFiles;
     274        41045 :     myStateDumpPeriod = string2time(oc.getString("save-state.period"));
     275        41045 :     myStateDumpPrefix = oc.getString("save-state.prefix");
     276        41045 :     myStateDumpSuffix = oc.getString("save-state.suffix");
     277              : 
     278              :     // initialise performance computation
     279        41045 :     mySimBeginMillis = SysUtils::getCurrentMillis();
     280        41045 :     myTraCIMillis = 0;
     281        41045 :     myHasInternalLinks = hasInternalLinks;
     282        41045 :     myJunctionHigherSpeeds = junctionHigherSpeeds;
     283        41045 :     myHasElevation = checkElevation();
     284        41045 :     myHasPedestrianNetwork = checkWalkingarea();
     285        41045 :     myHasBidiEdges = checkBidiEdges();
     286              :     myVersion = version;
     287        41045 :     if ((!MSGlobals::gUsingInternalLanes || !myHasInternalLinks)
     288        17757 :             && MSGlobals::gWeightsSeparateTurns > 0) {
     289           20 :         throw ProcessError(TL("Option weights.separate-turns is only supported when simulating with internal lanes"));
     290              :     }
     291        41035 : }
     292              : 
     293              : 
     294        73340 : MSNet::~MSNet() {
     295        40903 :     cleanupStatic();
     296              :     // delete controls
     297        40903 :     delete myJunctions;
     298        40903 :     delete myDetectorControl;
     299              :     // delete mean data
     300        40903 :     delete myEdges;
     301        40903 :     delete myInserter;
     302        40903 :     myInserter = nullptr;
     303        40903 :     delete myLogics;
     304        40903 :     delete myRouteLoaders;
     305        40903 :     if (myPersonControl != nullptr) {
     306         8075 :         delete myPersonControl;
     307         8075 :         myPersonControl = nullptr; // just to have that clear for later cleanups
     308              :     }
     309        40903 :     if (myContainerControl != nullptr) {
     310         1950 :         delete myContainerControl;
     311         1950 :         myContainerControl = nullptr; // just to have that clear for later cleanups
     312              :     }
     313        40903 :     delete myVehicleControl; // must happen after deleting transportables
     314              :     // delete events late so that vehicles can get rid of references first
     315        40903 :     delete myBeginOfTimestepEvents;
     316        40903 :     myBeginOfTimestepEvents = nullptr;
     317        40903 :     delete myEndOfTimestepEvents;
     318        40903 :     myEndOfTimestepEvents = nullptr;
     319        40903 :     delete myInsertionEvents;
     320        40903 :     myInsertionEvents = nullptr;
     321        40903 :     delete myShapeContainer;
     322        40903 :     delete myEdgeWeights;
     323        42256 :     for (auto& router : myRouterTT) {
     324         1353 :         delete router.second;
     325              :     }
     326              :     myRouterTT.clear();
     327        40914 :     for (auto& router : myRouterEffort) {
     328           11 :         delete router.second;
     329              :     }
     330              :     myRouterEffort.clear();
     331        43710 :     for (auto& router : myPedestrianRouter) {
     332         2807 :         delete router.second;
     333              :     }
     334              :     myPedestrianRouter.clear();
     335        44817 :     for (auto& router : myIntermodalRouter) {
     336         3914 :         delete router.second;
     337              :     }
     338              :     myIntermodalRouter.clear();
     339              :     myLanesRTree.second.RemoveAll();
     340        40920 :     for (MSTractionSubstation* sub : myTractionSubstations) {
     341           17 :         delete sub;
     342              :     }
     343              :     myTractionSubstations.clear();
     344        40903 :     clearAll();
     345        40903 :     if (MSGlobals::gUseMesoSim) {
     346         6246 :         delete MSGlobals::gMesoNet;
     347              :     }
     348        40903 :     myInstance = nullptr;
     349       155146 : }
     350              : 
     351              : 
     352              : void
     353          217 : MSNet::addRestriction(const std::string& id, const SUMOVehicleClass svc, const double speed) {
     354          217 :     myRestrictions[id][svc] = speed;
     355          217 : }
     356              : 
     357              : 
     358              : const std::map<SUMOVehicleClass, double>*
     359      2075857 : MSNet::getRestrictions(const std::string& id) const {
     360              :     std::map<std::string, std::map<SUMOVehicleClass, double> >::const_iterator i = myRestrictions.find(id);
     361      2075857 :     if (i == myRestrictions.end()) {
     362              :         return nullptr;
     363              :     }
     364         1094 :     return &i->second;
     365              : }
     366              : 
     367              : 
     368              : double
     369         3311 : MSNet::getPreference(const std::string& routingType, const SUMOVTypeParameter& pars) const {
     370         3311 :     if (gRoutingPreferences) {
     371         3311 :         auto it = myVTypePreferences.find(pars.id);
     372         3311 :         if (it != myVTypePreferences.end()) {
     373              :             auto it2 = it->second.find(routingType);
     374          224 :             if (it2 != it->second.end()) {
     375           56 :                 return it2->second;
     376              :             }
     377              :         }
     378              :         auto it3 = myVClassPreferences.find(pars.vehicleClass);
     379         3255 :         if (it3 != myVClassPreferences.end()) {
     380              :             auto it4 = it3->second.find(routingType);
     381          336 :             if (it4 != it3->second.end()) {
     382           84 :                 return it4->second;
     383              :             }
     384              :         }
     385              :         // fallback to generel preferences
     386         3171 :         it = myVTypePreferences.find("");
     387         3171 :         if (it != myVTypePreferences.end()) {
     388              :             auto it2 = it->second.find(routingType);
     389         1995 :             if (it2 != it->second.end()) {
     390          336 :                 return it2->second;
     391              :             }
     392              :         }
     393              :     }
     394              :     return 1;
     395              : }
     396              : 
     397              : 
     398              : void
     399           28 : MSNet::addPreference(const std::string& routingType, SUMOVehicleClass svc, double prio) {
     400           28 :     myVClassPreferences[svc][routingType] = prio;
     401           28 :     gRoutingPreferences = true;
     402           28 : }
     403              : 
     404              : 
     405              : void
     406           56 : MSNet::addPreference(const std::string& routingType, std::string vType, double prio) {
     407           56 :     myVTypePreferences[vType][routingType] = prio;
     408           56 :     gRoutingPreferences = true;
     409           56 : }
     410              : 
     411              : void
     412           24 : MSNet::addMesoType(const std::string& typeID, const MESegment::MesoEdgeType& edgeType) {
     413           24 :     myMesoEdgeTypes[typeID] = edgeType;
     414           24 : }
     415              : 
     416              : const MESegment::MesoEdgeType&
     417       804397 : MSNet::getMesoType(const std::string& typeID) {
     418              :     if (myMesoEdgeTypes.count(typeID) == 0) {
     419              :         // init defaults
     420         6810 :         const OptionsCont& oc = OptionsCont::getOptions();
     421              :         MESegment::MesoEdgeType edgeType;
     422         6810 :         edgeType.tauff = string2time(oc.getString("meso-tauff"));
     423         6810 :         edgeType.taufj = string2time(oc.getString("meso-taufj"));
     424         6810 :         edgeType.taujf = string2time(oc.getString("meso-taujf"));
     425         6810 :         edgeType.taujj = string2time(oc.getString("meso-taujj"));
     426         6810 :         edgeType.jamThreshold = oc.getFloat("meso-jam-threshold");
     427         6810 :         edgeType.junctionControl = oc.getBool("meso-junction-control");
     428         6810 :         edgeType.tlsPenalty = oc.getFloat("meso-tls-penalty");
     429         6810 :         edgeType.tlsFlowPenalty = oc.getFloat("meso-tls-flow-penalty");
     430         6810 :         edgeType.minorPenalty = string2time(oc.getString("meso-minor-penalty"));
     431         6810 :         edgeType.overtaking = oc.getBool("meso-overtaking");
     432         6810 :         edgeType.edgeLength = oc.getFloat("meso-edgelength");
     433         6810 :         myMesoEdgeTypes[typeID] = edgeType;
     434              :     }
     435       804397 :     return myMesoEdgeTypes[typeID];
     436              : }
     437              : 
     438              : 
     439              : bool
     440      7615849 : MSNet::hasFlow(const std::string& id) const {
     441              :     // inserter is deleted at the end of the simulation
     442      7615849 :     return myInserter != nullptr && myInserter->hasFlow(id);
     443              : }
     444              : 
     445              : 
     446              : MSNet::SimulationState
     447        31024 : MSNet::simulate(SUMOTime start, SUMOTime stop) {
     448              :     // report the begin when wished
     449        62048 :     WRITE_MESSAGEF(TL("Simulation version % started with time: %."), VERSION_STRING, time2string(start));
     450              :     // the simulation loop
     451              :     SimulationState state = SIMSTATE_RUNNING;
     452              :     // state loading may have changed the start time so we need to reinit it
     453        31024 :     myStep = start;
     454              :     int numSteps = 0;
     455              :     bool doStepLog = false;
     456     45732978 :     while (state == SIMSTATE_RUNNING) {
     457     45702357 :         doStepLog = myLogStepNumber && (numSteps % myLogStepPeriod == 0);
     458              :         if (doStepLog) {
     459          113 :             preSimStepOutput();
     460              :         }
     461     45702357 :         simulationStep();
     462     45701954 :         if (doStepLog) {
     463          113 :             postSimStepOutput();
     464              :         }
     465     45701954 :         state = adaptToState(simulationState(stop));
     466              : #ifdef DEBUG_SIMSTEP
     467              :         std::cout << SIMTIME << " MSNet::simulate(" << start << ", " << stop << ")"
     468              :                   << "\n simulation state: " << getStateMessage(state)
     469              :                   << std::endl;
     470              : #endif
     471     45701954 :         numSteps++;
     472              :     }
     473        30621 :     if (myLogStepNumber && !doStepLog) {
     474              :         // ensure some output on the last step
     475           16 :         preSimStepOutput();
     476           16 :         postSimStepOutput();
     477              :     }
     478              :     // exit simulation loop
     479        30621 :     if (myLogStepNumber) {
     480              :         // start new line for final verbose output
     481           20 :         std::cout << "\n";
     482              :     }
     483        30621 :     closeSimulation(start, getStateMessage(state));
     484        30621 :     return state;
     485              : }
     486              : 
     487              : 
     488              : void
     489     55384113 : MSNet::loadRoutes() {
     490     55384113 :     myRouteLoaders->loadNext(myStep);
     491     55383529 : }
     492              : 
     493              : 
     494              : const std::string
     495        12761 : MSNet::generateStatistics(const SUMOTime start, const long now) {
     496        12761 :     std::ostringstream msg;
     497        12761 :     if (myLogExecutionTime) {
     498        12443 :         const long duration = now - mySimBeginMillis;
     499              :         // print performance notice
     500        24886 :         msg << "Performance:\n" << " Duration: " << elapsedMs2string(duration) << "\n";
     501        12443 :         if (duration != 0) {
     502        12272 :             if (TraCIServer::getInstance() != nullptr) {
     503         4230 :                 msg << " TraCI-Duration: " << elapsedMs2string(myTraCIMillis) << "\n";
     504              :             }
     505        12272 :             msg << " Real time factor: " << (STEPS2TIME(myStep - start) * 1000. / (double)duration) << "\n";
     506              :             msg.setf(std::ios::fixed, std::ios::floatfield);     // use decimal format
     507              :             msg.setf(std::ios::showpoint);    // print decimal point
     508        12272 :             msg << " UPS: " << ((double)myVehiclesMoved / ((double)duration / 1000)) << "\n";
     509        12272 :             if (myPersonsMoved > 0) {
     510         2330 :                 msg << " UPS-Persons: " << ((double)myPersonsMoved / ((double)duration / 1000)) << "\n";
     511              :             }
     512              :         }
     513              :         // print vehicle statistics
     514        12443 :         const std::string vehDiscardNotice = ((myVehicleControl->getLoadedVehicleNo() != myVehicleControl->getDepartedVehicleNo()) ?
     515        16436 :                                               " (Loaded: " + toString(myVehicleControl->getLoadedVehicleNo()) + ")" : "");
     516              :         msg << "Vehicles:\n"
     517        12443 :             << " Inserted: " << myVehicleControl->getDepartedVehicleNo() << vehDiscardNotice << "\n"
     518        24886 :             << " Running: " << myVehicleControl->getRunningVehicleNo() << "\n"
     519        24886 :             << " Waiting: " << myInserter->getWaitingVehicleNo() << "\n";
     520              : 
     521        12443 :         if (myVehicleControl->getTeleportCount() > 0 || myVehicleControl->getCollisionCount() > 0) {
     522              :             // print optional teleport statistics
     523              :             std::vector<std::string> reasons;
     524          648 :             if (myVehicleControl->getCollisionCount() > 0) {
     525          628 :                 reasons.push_back("Collisions: " + toString(myVehicleControl->getCollisionCount()));
     526              :             }
     527          648 :             if (myVehicleControl->getTeleportsJam() > 0) {
     528          394 :                 reasons.push_back("Jam: " + toString(myVehicleControl->getTeleportsJam()));
     529              :             }
     530          648 :             if (myVehicleControl->getTeleportsYield() > 0) {
     531          190 :                 reasons.push_back("Yield: " + toString(myVehicleControl->getTeleportsYield()));
     532              :             }
     533          648 :             if (myVehicleControl->getTeleportsWrongLane() > 0) {
     534          254 :                 reasons.push_back("Wrong Lane: " + toString(myVehicleControl->getTeleportsWrongLane()));
     535              :             }
     536         1944 :             msg << " Teleports: " << myVehicleControl->getTeleportCount() << " (" << joinToString(reasons, ", ") << ")\n";
     537          648 :         }
     538        12443 :         if (myVehicleControl->getEmergencyStops() > 0) {
     539           60 :             msg << " Emergency Stops: " << myVehicleControl->getEmergencyStops() << "\n";
     540              :         }
     541        12443 :         if (myVehicleControl->getEmergencyBrakingCount() > 0) {
     542          285 :             msg << " Emergency Braking: " << myVehicleControl->getEmergencyBrakingCount() << "\n";
     543              :         }
     544        12443 :         if (myPersonControl != nullptr && myPersonControl->getLoadedNumber() > 0) {
     545         2376 :             const std::string discardNotice = ((myPersonControl->getLoadedNumber() != myPersonControl->getDepartedNumber()) ?
     546         2697 :                                                " (Loaded: " + toString(myPersonControl->getLoadedNumber()) + ")" : "");
     547              :             msg << "Persons:\n"
     548         2376 :                 << " Inserted: " << myPersonControl->getDepartedNumber() << discardNotice << "\n"
     549         4752 :                 << " Running: " << myPersonControl->getRunningNumber() << "\n";
     550         2376 :             if (myPersonControl->getJammedNumber() > 0) {
     551           53 :                 msg << " Jammed: " << myPersonControl->getJammedNumber() << "\n";
     552              :             }
     553         2376 :             if (myPersonControl->getTeleportCount() > 0) {
     554              :                 std::vector<std::string> reasons;
     555            7 :                 if (myPersonControl->getTeleportsAbortWait() > 0) {
     556            0 :                     reasons.push_back("Abort Wait: " + toString(myPersonControl->getTeleportsAbortWait()));
     557              :                 }
     558            7 :                 if (myPersonControl->getTeleportsWrongDest() > 0) {
     559           14 :                     reasons.push_back("Wrong Dest: " + toString(myPersonControl->getTeleportsWrongDest()));
     560              :                 }
     561           21 :                 msg << " Teleports: " << myPersonControl->getTeleportCount() << " (" << joinToString(reasons, ", ") << ")\n";
     562            7 :             }
     563              :         }
     564        12443 :         if (myContainerControl != nullptr && myContainerControl->getLoadedNumber() > 0) {
     565           76 :             const std::string discardNotice = ((myContainerControl->getLoadedNumber() != myContainerControl->getDepartedNumber()) ?
     566           76 :                                                " (Loaded: " + toString(myContainerControl->getLoadedNumber()) + ")" : "");
     567              :             msg << "Containers:\n"
     568           76 :                 << " Inserted: " << myContainerControl->getDepartedNumber() << "\n"
     569          152 :                 << " Running: " << myContainerControl->getRunningNumber() << "\n";
     570           76 :             if (myContainerControl->getJammedNumber() > 0) {
     571            0 :                 msg << " Jammed: " << myContainerControl->getJammedNumber() << "\n";
     572              :             }
     573           76 :             if (myContainerControl->getTeleportCount() > 0) {
     574              :                 std::vector<std::string> reasons;
     575            0 :                 if (myContainerControl->getTeleportsAbortWait() > 0) {
     576            0 :                     reasons.push_back("Abort Wait: " + toString(myContainerControl->getTeleportsAbortWait()));
     577              :                 }
     578            0 :                 if (myContainerControl->getTeleportsWrongDest() > 0) {
     579            0 :                     reasons.push_back("Wrong Dest: " + toString(myContainerControl->getTeleportsWrongDest()));
     580              :                 }
     581            0 :                 msg << " Teleports: " << myContainerControl->getTeleportCount() << " (" << joinToString(reasons, ", ") << ")\n";
     582            0 :             }
     583              :         }
     584              :     }
     585        25522 :     if (OptionsCont::getOptions().getBool("duration-log.statistics")) {
     586         6218 :         msg << MSDevice_Tripinfo::printStatistics();
     587              :     }
     588              :     std::string result = msg.str();
     589              :     result.erase(result.end() - 1);
     590        12761 :     return result;
     591        12761 : }
     592              : 
     593              : 
     594              : void
     595        10284 : MSNet::writeCollisions() const {
     596        20568 :     OutputDevice& od = OutputDevice::getDeviceByOption("collision-output");
     597        10438 :     for (const auto& item : myCollisions) {
     598          308 :         for (const auto& c : item.second) {
     599          154 :             if (c.time != SIMSTEP) {
     600           17 :                 continue;
     601              :             }
     602          274 :             od.openTag("collision");
     603          137 :             od.writeAttr("time", time2string(getCurrentTimeStep()));
     604          137 :             od.writeAttr("type", c.type);
     605          137 :             od.writeAttr("lane", c.lane->getID());
     606          137 :             od.writeAttr("pos", c.pos);
     607          137 :             od.writeAttr("collider", item.first);
     608          137 :             od.writeAttr("victim", c.victim);
     609          137 :             od.writeAttr("colliderType", c.colliderType);
     610          137 :             od.writeAttr("victimType", c.victimType);
     611          137 :             od.writeAttr("colliderSpeed", c.colliderSpeed);
     612          137 :             od.writeAttr("victimSpeed", c.victimSpeed);
     613          137 :             od.writeAttr("colliderFront", c.colliderFront);
     614          137 :             od.writeAttr("colliderBack", c.colliderBack);
     615          137 :             od.writeAttr("victimFront", c.victimFront);
     616          137 :             od.writeAttr("victimBack", c.victimBack);
     617          274 :             od.closeTag();
     618              :         }
     619              :     }
     620        10284 : }
     621              : 
     622              : 
     623              : void
     624          379 : MSNet::writeStatistics(const SUMOTime start, const long now) const {
     625          379 :     const long duration = now - mySimBeginMillis;
     626          379 :     OutputDevice& od = OutputDevice::getDeviceByOption("statistic-output");
     627          379 :     od.openTag("performance");
     628          379 :     od.writeAttr("clockBegin", time2string(mySimBeginMillis));
     629          379 :     od.writeAttr("clockEnd", time2string(now));
     630          379 :     od.writeAttr("clockDuration", time2string(duration));
     631          379 :     od.writeAttr("traciDuration", time2string(myTraCIMillis));
     632          379 :     od.writeAttr("realTimeFactor", duration != 0 ? (double)(myStep - start) / (double)duration : -1);
     633          379 :     od.writeAttr("vehicleUpdatesPerSecond", duration != 0 ? (double)myVehiclesMoved / ((double)duration / 1000) : -1);
     634          379 :     od.writeAttr("personUpdatesPerSecond", duration != 0 ? (double)myPersonsMoved / ((double)duration / 1000) : -1);
     635          379 :     od.writeAttr("begin", time2string(start));
     636          379 :     od.writeAttr("end", time2string(myStep));
     637          379 :     od.writeAttr("duration", time2string(myStep - start));
     638          379 :     od.closeTag();
     639          379 :     od.openTag("vehicles");
     640          379 :     od.writeAttr("loaded", myVehicleControl->getLoadedVehicleNo());
     641          379 :     od.writeAttr("inserted", myVehicleControl->getDepartedVehicleNo());
     642          379 :     od.writeAttr("running", myVehicleControl->getRunningVehicleNo());
     643          379 :     od.writeAttr("waiting", myInserter->getWaitingVehicleNo());
     644          379 :     od.closeTag();
     645          379 :     od.openTag("teleports");
     646          379 :     od.writeAttr("total", myVehicleControl->getTeleportCount());
     647          379 :     od.writeAttr("jam", myVehicleControl->getTeleportsJam());
     648          379 :     od.writeAttr("yield", myVehicleControl->getTeleportsYield());
     649          379 :     od.writeAttr("wrongLane", myVehicleControl->getTeleportsWrongLane());
     650          379 :     od.closeTag();
     651          379 :     od.openTag("safety");
     652          379 :     od.writeAttr("collisions", myVehicleControl->getCollisionCount());
     653          379 :     od.writeAttr("emergencyStops", myVehicleControl->getEmergencyStops());
     654          379 :     od.writeAttr("emergencyBraking", myVehicleControl->getEmergencyBrakingCount());
     655          379 :     od.closeTag();
     656          379 :     od.openTag("persons");
     657          385 :     od.writeAttr("loaded", myPersonControl != nullptr ? myPersonControl->getLoadedNumber() : 0);
     658          385 :     od.writeAttr("running", myPersonControl != nullptr ? myPersonControl->getRunningNumber() : 0);
     659          385 :     od.writeAttr("jammed", myPersonControl != nullptr ? myPersonControl->getJammedNumber() : 0);
     660          379 :     od.closeTag();
     661          379 :     od.openTag("personTeleports");
     662          385 :     od.writeAttr("total", myPersonControl != nullptr ? myPersonControl->getTeleportCount() : 0);
     663          385 :     od.writeAttr("abortWait", myPersonControl != nullptr ? myPersonControl->getTeleportsAbortWait() : 0);
     664          385 :     od.writeAttr("wrongDest", myPersonControl != nullptr ? myPersonControl->getTeleportsWrongDest() : 0);
     665          379 :     od.closeTag();
     666          603 :     if (OptionsCont::getOptions().isSet("tripinfo-output") || OptionsCont::getOptions().getBool("duration-log.statistics")) {
     667          264 :         MSDevice_Tripinfo::writeStatistics(od);
     668              :     }
     669          379 : }
     670              : 
     671              : 
     672              : void
     673     55382879 : MSNet::writeSummaryOutput(bool finalStep) {
     674              :     // summary output
     675     55382879 :     const OptionsCont& oc = OptionsCont::getOptions();
     676     55382879 :     const bool hasOutput = oc.isSet("summary-output");
     677     55382879 :     const bool hasPersonOutput = oc.isSet("person-summary-output");
     678     55382879 :     if (hasOutput || hasPersonOutput) {
     679       532296 :         const SUMOTime period = string2time(oc.getString("summary-output.period"));
     680       532296 :         const SUMOTime begin = string2time(oc.getString("begin"));
     681       532296 :         if ((period > 0 && (myStep - begin) % period != 0 && !finalStep)
     682              :                 // it's the final step but we already wrote output
     683       531376 :                 || (finalStep && (period <= 0 || (myStep - begin) % period == 0))) {
     684              :             return;
     685              :         }
     686              :     }
     687       530853 :     if (hasOutput) {
     688       523101 :         OutputDevice& od = OutputDevice::getDeviceByOption("summary-output");
     689       523101 :         int departedVehiclesNumber = myVehicleControl->getDepartedVehicleNo();
     690       523101 :         const double meanWaitingTime = departedVehiclesNumber != 0 ? myVehicleControl->getTotalDepartureDelay() / (double) departedVehiclesNumber : -1.;
     691              :         int endedVehicleNumber = myVehicleControl->getEndedVehicleNo();
     692       523101 :         const double meanTravelTime = endedVehicleNumber != 0 ? myVehicleControl->getTotalTravelTime() / (double) endedVehicleNumber : -1.;
     693       523101 :         od.openTag("step");
     694       523101 :         od.writeAttr("time", time2string(myStep));
     695       523101 :         od.writeAttr("loaded", myVehicleControl->getLoadedVehicleNo());
     696       523101 :         od.writeAttr("inserted", myVehicleControl->getDepartedVehicleNo());
     697       523101 :         od.writeAttr("running", myVehicleControl->getRunningVehicleNo());
     698       523101 :         od.writeAttr("waiting", myInserter->getWaitingVehicleNo());
     699       523101 :         od.writeAttr("ended", myVehicleControl->getEndedVehicleNo());
     700       523101 :         od.writeAttr("arrived", myVehicleControl->getArrivedVehicleNo());
     701       523101 :         od.writeAttr("collisions", myVehicleControl->getCollisionCount());
     702       523101 :         od.writeAttr("teleports", myVehicleControl->getTeleportCount());
     703       523101 :         od.writeAttr("halting", myVehicleControl->getHaltingVehicleNo());
     704       523101 :         od.writeAttr("stopped", myVehicleControl->getStoppedVehiclesCount());
     705       523101 :         od.writeAttr("meanWaitingTime", meanWaitingTime);
     706       523101 :         od.writeAttr("meanTravelTime", meanTravelTime);
     707       523101 :         std::pair<double, double> meanSpeed = myVehicleControl->getVehicleMeanSpeeds();
     708       523101 :         od.writeAttr("meanSpeed", meanSpeed.first);
     709       523101 :         od.writeAttr("meanSpeedRelative", meanSpeed.second);
     710       523101 :         od.writeAttr("discarded", myVehicleControl->getDiscardedVehicleNo());
     711       523101 :         if (myLogExecutionTime) {
     712       235817 :             od.writeAttr("duration", mySimStepDuration);
     713              :         }
     714      1046202 :         od.closeTag();
     715              :     }
     716     55381436 :     if (hasPersonOutput) {
     717         7752 :         OutputDevice& od = OutputDevice::getDeviceByOption("person-summary-output");
     718         7752 :         MSTransportableControl& pc = getPersonControl();
     719         7752 :         od.openTag("step");
     720        15504 :         od.writeAttr("time", time2string(myStep));
     721         7752 :         od.writeAttr("loaded", pc.getLoadedNumber());
     722         7752 :         od.writeAttr("inserted", pc.getDepartedNumber());
     723         7752 :         od.writeAttr("walking", pc.getMovingNumber());
     724         7752 :         od.writeAttr("waitingForRide", pc.getWaitingForVehicleNumber());
     725         7752 :         od.writeAttr("riding", pc.getRidingNumber());
     726         7752 :         od.writeAttr("stopping", pc.getWaitingUntilNumber());
     727         7752 :         od.writeAttr("jammed", pc.getJammedNumber());
     728         7752 :         od.writeAttr("ended", pc.getEndedNumber());
     729         7752 :         od.writeAttr("arrived", pc.getArrivedNumber());
     730         7752 :         od.writeAttr("teleports", pc.getTeleportCount());
     731         7752 :         od.writeAttr("discarded", pc.getDiscardedNumber());
     732         7752 :         if (myLogExecutionTime) {
     733            0 :             od.writeAttr("duration", mySimStepDuration);
     734              :         }
     735        15504 :         od.closeTag();
     736              :     }
     737              : }
     738              : 
     739              : 
     740              : void
     741        39412 : MSNet::closeSimulation(SUMOTime start, const std::string& reason) {
     742              :     // report the end when wished
     743        78824 :     WRITE_MESSAGE(TLF("Simulation ended at time: %.", time2string(getCurrentTimeStep())));
     744        39412 :     if (reason != "") {
     745        77980 :         WRITE_MESSAGE(TL("Reason: ") + reason);
     746              :     }
     747        39412 :     myDetectorControl->close(myStep);
     748        40853 :     if (MSStopOut::active() && OptionsCont::getOptions().getBool("stop-output.write-unfinished")) {
     749          120 :         MSStopOut::getInstance()->generateOutputForUnfinished();
     750              :     }
     751        39412 :     MSDevice_Vehroutes::writePendingOutput(OptionsCont::getOptions().getBool("vehroute-output.write-unfinished"));
     752        78824 :     if (OptionsCont::getOptions().getBool("tripinfo-output.write-unfinished")) {
     753          948 :         MSDevice_Tripinfo::generateOutputForUnfinished();
     754              :     }
     755        78824 :     if (OptionsCont::getOptions().isSet("chargingstations-output")) {
     756          226 :         if (!OptionsCont::getOptions().getBool("chargingstations-output.aggregated")) {
     757           93 :             writeChargingStationOutput();
     758           40 :         } else if (OptionsCont::getOptions().getBool("chargingstations-output.aggregated.write-unfinished")) {
     759           12 :             MSChargingStationExport::write(OutputDevice::getDeviceByOption("chargingstations-output"), true);
     760              :         }
     761              :     }
     762        78824 :     if (OptionsCont::getOptions().isSet("overheadwiresegments-output")) {
     763            5 :         writeOverheadWireSegmentOutput();
     764              :     }
     765        78824 :     if (OptionsCont::getOptions().isSet("substations-output")) {
     766            5 :         writeSubstationOutput();
     767              :     }
     768        39412 :     writeRailSignalBlocks();
     769        39412 :     const long now = SysUtils::getCurrentMillis();
     770        66381 :     if (myLogExecutionTime || OptionsCont::getOptions().getBool("duration-log.statistics")) {
     771        25522 :         WRITE_MESSAGE(generateStatistics(start, now));
     772              :     }
     773        78824 :     if (OptionsCont::getOptions().isSet("statistic-output")) {
     774          379 :         writeStatistics(start, now);
     775              :     }
     776              :     // maybe write a final line of output if reporting is periodic
     777        39412 :     writeSummaryOutput(true);
     778        39412 : }
     779              : 
     780              : 
     781              : void
     782     55346623 : MSNet::simulationStep(const bool onlyMove) {
     783     55346623 :     if (myStepCompletionMissing) {
     784            4 :         postMoveStep();
     785            4 :         myStepCompletionMissing = false;
     786         2636 :         return;
     787              :     }
     788              : #ifdef DEBUG_SIMSTEP
     789              :     std::cout << SIMTIME << ": MSNet::simulationStep() called"
     790              :               << ", myStep = " << myStep
     791              :               << std::endl;
     792              : #endif
     793              :     TraCIServer* t = TraCIServer::getInstance();
     794              :     int lastTraCICmd = 0;
     795     55346619 :     if (t != nullptr) {
     796      8432749 :         if (myLogExecutionTime) {
     797      8236699 :             myTraCIStepDuration = SysUtils::getCurrentMillis();
     798              :         }
     799      8432749 :         lastTraCICmd = t->processCommands(myStep);
     800              : #ifdef DEBUG_SIMSTEP
     801              :         bool loadRequested = !TraCI::getLoadArgs().empty();
     802              :         assert(t->getTargetTime() >= myStep || loadRequested || TraCIServer::wasClosed());
     803              : #endif
     804      8432641 :         if (myLogExecutionTime) {
     805      8236617 :             myTraCIStepDuration = SysUtils::getCurrentMillis() - myTraCIStepDuration;
     806              :         }
     807      8432641 :         if (TraCIServer::wasClosed() || !t->getLoadArgs().empty()) {
     808              :             return;
     809              :         }
     810              :     }
     811              : #ifdef DEBUG_SIMSTEP
     812              :     std::cout << SIMTIME << ": TraCI target time: " << t->getTargetTime() << std::endl;
     813              : #endif
     814              :     // execute beginOfTimestepEvents
     815     55343883 :     if (myLogExecutionTime) {
     816     24533340 :         mySimStepDuration = SysUtils::getCurrentMillis();
     817              :     }
     818              :     // simulation state output
     819     55343883 :     std::vector<SUMOTime>::iterator timeIt = std::find(myStateDumpTimes.begin(), myStateDumpTimes.end(), myStep);
     820     55343883 :     if (timeIt != myStateDumpTimes.end()) {
     821          312 :         const int dist = (int)distance(myStateDumpTimes.begin(), timeIt);
     822          312 :         MSStateHandler::saveState(myStateDumpFiles[dist], myStep);
     823              :     }
     824     55343883 :     if (myStateDumpPeriod > 0 && myStep % myStateDumpPeriod == 0) {
     825           84 :         std::string timeStamp = time2string(myStep);
     826              :         std::replace(timeStamp.begin(), timeStamp.end(), ':', '-');
     827           84 :         const std::string filename = myStateDumpPrefix + "_" + timeStamp + myStateDumpSuffix;
     828           84 :         MSStateHandler::saveState(filename, myStep);
     829           84 :         myPeriodicStateFiles.push_back(filename);
     830           84 :         int keep = OptionsCont::getOptions().getInt("save-state.period.keep");
     831           84 :         if (keep > 0 && (int)myPeriodicStateFiles.size() > keep) {
     832            0 :             std::remove(myPeriodicStateFiles.front().c_str());
     833              :             myPeriodicStateFiles.erase(myPeriodicStateFiles.begin());
     834              :         }
     835              :     }
     836     55343883 :     myBeginOfTimestepEvents->execute(myStep);
     837     55343877 :     if (MSRailSignalControl::hasInstance()) {
     838      8411205 :         MSRailSignalControl::getInstance().updateSignals(myStep);
     839              :     }
     840              : #ifdef HAVE_FOX
     841     55343877 :     MSRoutingEngine::waitForAll();
     842              : #endif
     843     55343877 :     if (MSGlobals::gCheck4Accidents && !MSGlobals::gUseMesoSim) {
     844     42600965 :         myEdges->detectCollisions(myStep, STAGE_EVENTS);
     845              :     }
     846              :     // check whether the tls programs need to be switched
     847     55343877 :     myLogics->check2Switch(myStep);
     848              : 
     849     55343877 :     if (MSGlobals::gUseMesoSim) {
     850     12742912 :         MSGlobals::gMesoNet->simulate(myStep);
     851              :     } else {
     852              :         // assure all lanes with vehicles are 'active'
     853     42600965 :         myEdges->patchActiveLanes();
     854              : 
     855              :         // compute safe velocities for all vehicles for the next few lanes
     856              :         // also register ApproachingVehicleInformation for all links
     857     42600965 :         myEdges->planMovements(myStep);
     858              : 
     859              :         // register junction approaches based on planned velocities as basis for right-of-way decision
     860     42600965 :         myEdges->setJunctionApproaches();
     861              : 
     862              :         // decide right-of-way and execute movements
     863     42600965 :         myEdges->executeMovements(myStep);
     864     42600962 :         if (MSGlobals::gCheck4Accidents) {
     865     42600962 :             myEdges->detectCollisions(myStep, STAGE_MOVEMENTS);
     866              :         }
     867              : 
     868              :         // vehicles may change lanes
     869     42600962 :         myEdges->changeLanes(myStep);
     870              : 
     871     42600962 :         if (MSGlobals::gCheck4Accidents) {
     872     42600962 :             myEdges->detectCollisions(myStep, STAGE_LANECHANGE);
     873              :         }
     874              :     }
     875              :     // flush arrived meso vehicles and micro vehicles that were removed due to collision
     876     55343874 :     myVehicleControl->removePending();
     877     55343874 :     loadRoutes();
     878              : 
     879              :     // persons
     880     55343858 :     if (myPersonControl != nullptr && myPersonControl->hasTransportables()) {
     881      3478479 :         myPersonControl->checkWaiting(this, myStep);
     882              :     }
     883              :     // containers
     884     55343808 :     if (myContainerControl != nullptr && myContainerControl->hasTransportables()) {
     885      3638251 :         myContainerControl->checkWaiting(this, myStep);
     886              :     }
     887     55343808 :     if (MSRailSignalControl::hasInstance()) {
     888      8411205 :         MSRailSignalControl::getInstance().resetWaitRelations();
     889              :         // preserve waitRelation from insertion for the next step
     890              :     }
     891              :     // insert vehicles
     892     55343808 :     myInserter->determineCandidates(myStep);
     893     55343763 :     myInsertionEvents->execute(myStep);
     894              : #ifdef HAVE_FOX
     895     55343667 :     MSRoutingEngine::waitForAll();
     896              : #endif
     897     55343643 :     myInserter->emitVehicles(myStep);
     898     55343491 :     if (MSGlobals::gCheck4Accidents && !MSGlobals::gUseMesoSim) {
     899              :         //myEdges->patchActiveLanes(); // @note required to detect collisions on lanes that were empty before insertion. wasteful?
     900     42600689 :         myEdges->detectCollisions(myStep, STAGE_INSERTIONS);
     901              :     }
     902     55343491 :     MSVehicleTransfer::getInstance()->checkInsertions(myStep);
     903              : 
     904              :     // execute endOfTimestepEvents
     905     55343491 :     myEndOfTimestepEvents->execute(myStep);
     906              : 
     907     55343482 :     if (myLogExecutionTime) {
     908     24533170 :         myTraCIStepDuration -= SysUtils::getCurrentMillis();
     909              :     }
     910     55343482 :     if (onlyMove) {
     911            4 :         myStepCompletionMissing = true;
     912            4 :         return;
     913              :     }
     914     55343478 :     if (t != nullptr && lastTraCICmd == libsumo::CMD_EXECUTEMOVE) {
     915            6 :         t->processCommands(myStep, true);
     916              :     }
     917     55343478 :     postMoveStep();
     918              : }
     919              : 
     920              : 
     921              : void
     922     55343482 : MSNet::postMoveStep() {
     923     55343482 :     const int numControlled = libsumo::Helper::postProcessRemoteControl();
     924     55343482 :     if (numControlled > 0 && MSGlobals::gCheck4Accidents) {
     925         8922 :         myEdges->detectCollisions(myStep, STAGE_REMOTECONTROL);
     926              :     }
     927     55343482 :     if (myLogExecutionTime) {
     928     24533170 :         myTraCIStepDuration += SysUtils::getCurrentMillis();
     929     24533170 :         myTraCIMillis += myTraCIStepDuration;
     930              :     }
     931     55343482 :     if (MSGlobals::gCheck4Accidents && !MSGlobals::gUseMesoSim) {
     932              :         // collisions from the previous step were kept to avoid duplicate
     933              :         // warnings. we must remove them now to ensure correct output.
     934     42600684 :         removeOutdatedCollisions();
     935              :     }
     936              :     // update and write (if needed) detector values
     937     55343482 :     mySimStepDuration = SysUtils::getCurrentMillis() - mySimStepDuration;
     938     55343482 :     writeOutput();
     939              : 
     940     55343466 :     if (myLogExecutionTime) {
     941     24533170 :         myVehiclesMoved += myVehicleControl->getRunningVehicleNo();
     942     24533170 :         if (myPersonControl != nullptr) {
     943      2696203 :             myPersonsMoved += myPersonControl->getRunningNumber();
     944              :         }
     945              :     }
     946     55343466 :     myStep += DELTA_T;
     947     55343466 : }
     948              : 
     949              : 
     950              : MSNet::SimulationState
     951     55247328 : MSNet::simulationState(SUMOTime stopTime) const {
     952     55247328 :     if (TraCIServer::wasClosed()) {
     953              :         return SIMSTATE_CONNECTION_CLOSED;
     954              :     }
     955     55244577 :     if (TraCIServer::getInstance() != nullptr && !TraCIServer::getInstance()->getLoadArgs().empty()) {
     956              :         return SIMSTATE_LOADING;
     957              :     }
     958     55244564 :     if ((stopTime < 0 || myStep > stopTime) && TraCIServer::getInstance() == nullptr && (stopTime > 0 || myStep > myEdgeDataEndTime)) {
     959     30712704 :         if ((myVehicleControl->getActiveVehicleCount() == 0)
     960      5605387 :                 && (myInserter->getPendingFlowCount() == 0)
     961      1950205 :                 && (myPersonControl == nullptr || !myPersonControl->hasNonWaiting())
     962       408518 :                 && (myContainerControl == nullptr || !myContainerControl->hasNonWaiting())
     963     30773336 :                 && !MSDevice_Taxi::hasServableReservations()) {
     964              :             return SIMSTATE_NO_FURTHER_VEHICLES;
     965              :         }
     966              :     }
     967     55199032 :     if (stopTime >= 0 && myStep >= stopTime) {
     968              :         return SIMSTATE_END_STEP_REACHED;
     969              :     }
     970     55178528 :     if (myMaxTeleports >= 0 && myVehicleControl->getTeleportCount() > myMaxTeleports) {
     971              :         return SIMSTATE_TOO_MANY_TELEPORTS;
     972              :     }
     973     55178520 :     if (myAmInterrupted) {
     974           12 :         return SIMSTATE_INTERRUPTED;
     975              :     }
     976              :     return SIMSTATE_RUNNING;
     977              : }
     978              : 
     979              : 
     980              : MSNet::SimulationState
     981     55239141 : MSNet::adaptToState(MSNet::SimulationState state, const bool isLibsumo) const {
     982     55239141 :     if (state == SIMSTATE_LOADING) {
     983           13 :         OptionsIO::setArgs(TraCIServer::getInstance()->getLoadArgs());
     984              :         TraCIServer::getInstance()->getLoadArgs().clear();
     985     55239128 :     } else if (state != SIMSTATE_RUNNING && ((TraCIServer::getInstance() != nullptr && !TraCIServer::wasClosed()) || isLibsumo)) {
     986              :         // overrides SIMSTATE_END_STEP_REACHED, e.g. (TraCI / Libsumo ignore SUMO's --end option)
     987        23052 :         return SIMSTATE_RUNNING;
     988     55216076 :     } else if (state == SIMSTATE_NO_FURTHER_VEHICLES) {
     989        27525 :         if (myPersonControl != nullptr) {
     990         6751 :             myPersonControl->abortAnyWaitingForVehicle();
     991              :         }
     992        27525 :         if (myContainerControl != nullptr) {
     993         1863 :             myContainerControl->abortAnyWaitingForVehicle();
     994              :         }
     995        27525 :         myVehicleControl->abortWaiting();
     996              :     }
     997              :     return state;
     998              : }
     999              : 
    1000              : 
    1001              : std::string
    1002        38808 : MSNet::getStateMessage(MSNet::SimulationState state) {
    1003        38808 :     switch (state) {
    1004              :         case MSNet::SIMSTATE_RUNNING:
    1005          422 :             return "";
    1006              :         case MSNet::SIMSTATE_END_STEP_REACHED:
    1007         7836 :             return TL("The final simulation step has been reached.");
    1008              :         case MSNet::SIMSTATE_NO_FURTHER_VEHICLES:
    1009        27904 :             return TL("All vehicles have left the simulation.");
    1010              :         case MSNet::SIMSTATE_CONNECTION_CLOSED:
    1011         2615 :             return TL("TraCI requested termination.");
    1012              :         case MSNet::SIMSTATE_ERROR_IN_SIM:
    1013            0 :             return TL("An error occurred (see log).");
    1014              :         case MSNet::SIMSTATE_INTERRUPTED:
    1015           12 :             return TL("Interrupted.");
    1016              :         case MSNet::SIMSTATE_TOO_MANY_TELEPORTS:
    1017            6 :             return TL("Too many teleports.");
    1018              :         case MSNet::SIMSTATE_LOADING:
    1019           13 :             return TL("TraCI issued load command.");
    1020              :         default:
    1021            0 :             return TL("Unknown reason.");
    1022              :     }
    1023              : }
    1024              : 
    1025              : 
    1026              : void
    1027        41182 : MSNet::clearAll() {
    1028              :     // clear container
    1029        41182 :     MSEdge::clear();
    1030        41182 :     MSLane::clear();
    1031        41182 :     MSRoute::clear();
    1032        41182 :     delete MSVehicleTransfer::getInstance();
    1033        41182 :     MSDevice::cleanupAll();
    1034        41182 :     MSCalibrator::cleanup();
    1035        82861 :     while (!MSLaneSpeedTrigger::getInstances().empty()) {
    1036          497 :         delete MSLaneSpeedTrigger::getInstances().begin()->second;
    1037              :     }
    1038        45156 :     while (!MSTriggeredRerouter::getInstances().empty()) {
    1039         3974 :         delete MSTriggeredRerouter::getInstances().begin()->second;
    1040              :     }
    1041        41182 :     MSDevice_BTsender::cleanup();
    1042        41182 :     MSDevice_SSM::cleanup();
    1043        41182 :     MSDevice_ToC::cleanup();
    1044        41182 :     MSStopOut::cleanup();
    1045        41182 :     MSRailSignalConstraint::cleanup();
    1046        41182 :     MSRailSignalControl::cleanup();
    1047        41182 :     MSDriveWay::cleanup();
    1048              :     TraCIServer* t = TraCIServer::getInstance();
    1049        41182 :     if (t != nullptr) {
    1050         2739 :         t->cleanup();
    1051              :     }
    1052        41182 :     libsumo::Helper::cleanup();
    1053        41182 :     OutputDevice::closeAll(true);
    1054        41182 : }
    1055              : 
    1056              : 
    1057              : void
    1058          168 : MSNet::clearState(const SUMOTime step, bool quickReload) {
    1059          168 :     MSGlobals::gClearState = true;
    1060          168 :     if (MSGlobals::gUseMesoSim) {
    1061           16 :         MSGlobals::gMesoNet->clearState();
    1062          750 :         for (MSEdge* const edge : MSEdge::getAllEdges()) {
    1063         1488 :             for (MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*edge); s != nullptr; s = s->getNextSegment()) {
    1064          754 :                 s->clearState();
    1065              :             }
    1066              :         }
    1067              :     } else {
    1068         7184 :         for (MSEdge* const edge : MSEdge::getAllEdges()) {
    1069        15576 :             for (MSLane* const lane : edge->getLanes()) {
    1070         8544 :                 lane->getVehiclesSecure();
    1071         8544 :                 lane->clearState();
    1072         8544 :                 lane->releaseVehicles();
    1073              :             }
    1074         7032 :             edge->clearState();
    1075              :         }
    1076              :     }
    1077          168 :     myInserter->clearState();
    1078              :     // detectors may still reference persons/vehicles
    1079          168 :     myDetectorControl->updateDetectors(myStep);
    1080          168 :     myDetectorControl->writeOutput(myStep, true);
    1081          168 :     myDetectorControl->clearState(step);
    1082              : 
    1083          168 :     if (myPersonControl != nullptr) {
    1084           23 :         myPersonControl->clearState();
    1085              :     }
    1086          168 :     if (myContainerControl != nullptr) {
    1087            0 :         myContainerControl->clearState();
    1088              :     }
    1089              :     // delete vtypes after transportables have removed their types
    1090          168 :     myVehicleControl->clearState(true);
    1091          168 :     MSVehicleTransfer::getInstance()->clearState();
    1092          168 :     myLogics->clearState(step, quickReload);
    1093              :     // delete all routes after vehicles and detector output is done
    1094          168 :     MSRoute::dict_clearState();
    1095          209 :     for (auto& item : myStoppingPlaces) {
    1096           82 :         for (auto& item2 : item.second) {
    1097           41 :             item2.second->clearState();
    1098              :         }
    1099              :     }
    1100          168 :     myShapeContainer->clearState();
    1101          168 :     myBeginOfTimestepEvents->clearState(myStep, step);
    1102          168 :     myEndOfTimestepEvents->clearState(myStep, step);
    1103          168 :     myInsertionEvents->clearState(myStep, step);
    1104          168 :     MSRailSignalControl::clearState();
    1105          168 :     MSDriveWay::clearState();
    1106          168 :     myStep = step;
    1107          168 :     MSGlobals::gClearState = false;
    1108          168 : }
    1109              : 
    1110              : 
    1111              : void
    1112     55343482 : MSNet::writeOutput() {
    1113              :     // update detector values
    1114     55343482 :     myDetectorControl->updateDetectors(myStep);
    1115     55343473 :     const OptionsCont& oc = OptionsCont::getOptions();
    1116              : 
    1117              :     // check state dumps
    1118    110686946 :     if (oc.isSet("netstate-dump")) {
    1119        12936 :         MSXMLRawOut::write(OutputDevice::getDeviceByOption("netstate-dump"), *myEdges, myStep,
    1120              :                            oc.getInt("netstate-dump.precision"));
    1121              :     }
    1122              : 
    1123              :     // check fcd dumps
    1124    110686946 :     if (OptionsCont::getOptions().isSet("fcd-output")) {
    1125      7790074 :         if (OptionsCont::getOptions().isSet("person-fcd-output")) {
    1126           24 :             MSFCDExport::write(OutputDevice::getDeviceByOption("fcd-output"), myStep, SUMO_TAG_VEHICLE);
    1127           48 :             MSFCDExport::write(OutputDevice::getDeviceByOption("person-fcd-output"), myStep, SUMO_TAG_PERSON);
    1128              :         } else {
    1129      7790026 :             MSFCDExport::write(OutputDevice::getDeviceByOption("fcd-output"), myStep);
    1130              :         }
    1131              :     }
    1132              : 
    1133              :     // check emission dumps
    1134    110686946 :     if (OptionsCont::getOptions().isSet("emission-output")) {
    1135       215936 :         MSEmissionExport::write(OutputDevice::getDeviceByOption("emission-output"), myStep);
    1136              :     }
    1137              : 
    1138              :     // battery dumps
    1139    110686946 :     if (OptionsCont::getOptions().isSet("battery-output")) {
    1140       140516 :         MSBatteryExport::write(OutputDevice::getDeviceByOption("battery-output"), myStep,
    1141              :                                oc.getInt("battery-output.precision"));
    1142              :     }
    1143              : 
    1144              :     // charging station aggregated dumps
    1145     55430007 :     if (OptionsCont::getOptions().isSet("chargingstations-output") && OptionsCont::getOptions().getBool("chargingstations-output.aggregated")) {
    1146        22240 :         MSChargingStationExport::write(OutputDevice::getDeviceByOption("chargingstations-output"));
    1147              :     }
    1148              : 
    1149              :     // elecHybrid dumps
    1150    110686946 :     if (OptionsCont::getOptions().isSet("elechybrid-output")) {
    1151          450 :         std::string output = OptionsCont::getOptions().getString("elechybrid-output");
    1152              : 
    1153          900 :         if (oc.getBool("elechybrid-output.aggregated")) {
    1154              :             // build a xml file with aggregated device.elechybrid output
    1155          600 :             MSElecHybridExport::writeAggregated(OutputDevice::getDeviceByOption("elechybrid-output"), myStep,
    1156              :                                                 oc.getInt("elechybrid-output.precision"));
    1157              :         } else {
    1158              :             // build a separate xml file for each vehicle equipped with device.elechybrid
    1159              :             // RICE_TODO: Does this have to be placed here in MSNet.cpp ?
    1160          150 :             MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
    1161          204 :             for (MSVehicleControl::constVehIt it = vc.loadedVehBegin(); it != vc.loadedVehEnd(); ++it) {
    1162           54 :                 const SUMOVehicle* veh = it->second;
    1163           54 :                 if (!veh->isOnRoad()) {
    1164            0 :                     continue;
    1165              :                 }
    1166           54 :                 if (static_cast<MSDevice_ElecHybrid*>(veh->getDevice(typeid(MSDevice_ElecHybrid))) != nullptr) {
    1167              :                     std::string vehID = veh->getID();
    1168           54 :                     std::string filename2 = output + "_" + vehID + ".xml";
    1169           54 :                     OutputDevice& dev = OutputDevice::getDevice(filename2);
    1170              :                     std::map<SumoXMLAttr, std::string> attrs;
    1171           54 :                     attrs[SUMO_ATTR_VEHICLE] = vehID;
    1172           54 :                     attrs[SUMO_ATTR_MAXIMUMBATTERYCAPACITY] = toString(dynamic_cast<MSDevice_ElecHybrid*>(veh->getDevice(typeid(MSDevice_ElecHybrid)))->getMaximumBatteryCapacity());
    1173           54 :                     attrs[SUMO_ATTR_RECUPERATIONENABLE] = toString(MSGlobals::gOverheadWireRecuperation);
    1174          108 :                     dev.writeXMLHeader("elecHybrid-export", "", attrs);
    1175          108 :                     MSElecHybridExport::write(OutputDevice::getDevice(filename2), veh, myStep, oc.getInt("elechybrid-output.precision"));
    1176              :                 }
    1177              :             }
    1178              :         }
    1179              :     }
    1180              : 
    1181              : 
    1182              :     // check full dumps
    1183    110686946 :     if (OptionsCont::getOptions().isSet("full-output")) {
    1184         1138 :         MSGlobals::gHaveEmissions = true;
    1185         2276 :         MSFullExport::write(OutputDevice::getDeviceByOption("full-output"), myStep);
    1186              :     }
    1187              : 
    1188              :     // check queue dumps
    1189    110686946 :     if (OptionsCont::getOptions().isSet("queue-output")) {
    1190       325614 :         MSQueueExport::write(OutputDevice::getDeviceByOption("queue-output"), myStep);
    1191              :     }
    1192              : 
    1193              :     // check amitran dumps
    1194    110686946 :     if (OptionsCont::getOptions().isSet("amitran-output")) {
    1195         2040 :         MSAmitranTrajectories::write(OutputDevice::getDeviceByOption("amitran-output"), myStep);
    1196              :     }
    1197              : 
    1198              :     // check vtk dumps
    1199    110686946 :     if (OptionsCont::getOptions().isSet("vtk-output")) {
    1200              : 
    1201           60 :         if (MSNet::getInstance()->getVehicleControl().getRunningVehicleNo() > 0) {
    1202           60 :             std::string timestep = time2string(myStep);
    1203           60 :             if (TS >= 1.0) {
    1204           48 :                 timestep = timestep.substr(0, timestep.length() - 3);
    1205           36 :             } else if (DELTA_T % 100 == 0) {
    1206           72 :                 timestep = timestep.substr(0, timestep.length() - 1);
    1207              :             }
    1208           66 :             std::string output = OptionsCont::getOptions().getString("vtk-output");
    1209           66 :             std::string filename = output + "_" + timestep + ".vtp";
    1210              : 
    1211           60 :             OutputDevice_File dev(filename);
    1212              : 
    1213              :             //build a huge mass of xml files
    1214           54 :             MSVTKExport::write(dev, myStep);
    1215              : 
    1216           54 :         }
    1217              : 
    1218              :     }
    1219              : 
    1220     55343467 :     writeSummaryOutput();
    1221              : 
    1222              :     // write detector values
    1223     55343467 :     myDetectorControl->writeOutput(myStep + DELTA_T, false);
    1224              : 
    1225              :     // write link states
    1226    110686932 :     if (OptionsCont::getOptions().isSet("link-output")) {
    1227         4064 :         OutputDevice& od = OutputDevice::getDeviceByOption("link-output");
    1228         4064 :         od.openTag("timestep");
    1229         4064 :         od.writeAttr(SUMO_ATTR_ID, STEPS2TIME(myStep));
    1230        86288 :         for (const MSEdge* const edge : myEdges->getEdges()) {
    1231       181088 :             for (const MSLane* const lane : edge->getLanes()) {
    1232       206108 :                 for (const MSLink* const link : lane->getLinkCont()) {
    1233       214488 :                     link->writeApproaching(od, lane->getID());
    1234              :                 }
    1235              :             }
    1236              :         }
    1237         8128 :         od.closeTag();
    1238              :     }
    1239              : 
    1240              :     // write SSM output
    1241     57876572 :     for (MSDevice_SSM* dev : MSDevice_SSM::getInstances()) {
    1242      2533106 :         dev->updateAndWriteOutput();
    1243              :     }
    1244              : 
    1245              :     // write ToC output
    1246     55359185 :     for (MSDevice_ToC* dev : MSDevice_ToC::getInstances()) {
    1247        15719 :         if (dev->generatesOutput()) {
    1248        15513 :             dev->writeOutput();
    1249              :         }
    1250              :     }
    1251              : 
    1252    110686932 :     if (OptionsCont::getOptions().isSet("collision-output")) {
    1253        10284 :         writeCollisions();
    1254              :     }
    1255     55343466 : }
    1256              : 
    1257              : 
    1258              : bool
    1259            0 : MSNet::logSimulationDuration() const {
    1260            0 :     return myLogExecutionTime;
    1261              : }
    1262              : 
    1263              : 
    1264              : MSTransportableControl&
    1265     13481531 : MSNet::getPersonControl() {
    1266     13481531 :     if (myPersonControl == nullptr) {
    1267         6563 :         myPersonControl = new MSTransportableControl(true);
    1268              :     }
    1269     13481507 :     return *myPersonControl;
    1270              : }
    1271              : 
    1272              : 
    1273              : MSTransportableControl&
    1274      6454969 : MSNet::getContainerControl() {
    1275      6454969 :     if (myContainerControl == nullptr) {
    1276         1782 :         myContainerControl = new MSTransportableControl(false);
    1277              :     }
    1278      6454969 :     return *myContainerControl;
    1279              : }
    1280              : 
    1281              : MSDynamicShapeUpdater*
    1282           23 : MSNet::makeDynamicShapeUpdater() {
    1283           23 :     myDynamicShapeUpdater = std::unique_ptr<MSDynamicShapeUpdater> (new MSDynamicShapeUpdater(*myShapeContainer));
    1284           23 :     return myDynamicShapeUpdater.get();
    1285              : }
    1286              : 
    1287              : MSEdgeWeightsStorage&
    1288      6822348 : MSNet::getWeightsStorage() {
    1289      6822348 :     if (myEdgeWeights == nullptr) {
    1290         1782 :         myEdgeWeights = new MSEdgeWeightsStorage();
    1291              :     }
    1292      6822348 :     return *myEdgeWeights;
    1293              : }
    1294              : 
    1295              : 
    1296              : void
    1297          129 : MSNet::preSimStepOutput() const {
    1298          129 :     std::cout << "Step #" << time2string(myStep);
    1299          129 : }
    1300              : 
    1301              : 
    1302              : void
    1303          129 : MSNet::postSimStepOutput() const {
    1304          129 :     if (myLogExecutionTime) {
    1305          127 :         std::ostringstream oss;
    1306              :         oss.setf(std::ios::fixed, std::ios::floatfield);     // use decimal format
    1307              :         oss.setf(std::ios::showpoint);    // print decimal point
    1308          127 :         oss << std::setprecision(gPrecision);
    1309          127 :         if (mySimStepDuration != 0) {
    1310           70 :             const double durationSec = (double)mySimStepDuration / 1000.;
    1311           70 :             oss << " (" << mySimStepDuration << "ms ~= "
    1312           70 :                 << (TS / durationSec) << "*RT, ~"
    1313           70 :                 << ((double) myVehicleControl->getRunningVehicleNo() / durationSec);
    1314              :         } else {
    1315           57 :             oss << " (0ms ?*RT. ?";
    1316              :         }
    1317          127 :         oss << "UPS, ";
    1318          127 :         if (TraCIServer::getInstance() != nullptr) {
    1319           79 :             oss << "TraCI: " << myTraCIStepDuration << "ms, ";
    1320              :         }
    1321          127 :         oss << "vehicles TOT " << myVehicleControl->getDepartedVehicleNo()
    1322          254 :             << " ACT " << myVehicleControl->getRunningVehicleNo()
    1323          127 :             << " BUF " << myInserter->getWaitingVehicleNo()
    1324          127 :             << ")                                              ";
    1325          254 :         std::string prev = "Step #" + time2string(myStep - DELTA_T);
    1326          254 :         std::cout << oss.str().substr(0, 90 - prev.length());
    1327          127 :     }
    1328          129 :     std::cout << '\r';
    1329          129 : }
    1330              : 
    1331              : 
    1332              : void
    1333        11166 : MSNet::addVehicleStateListener(VehicleStateListener* listener) {
    1334        11166 :     if (find(myVehicleStateListeners.begin(), myVehicleStateListeners.end(), listener) == myVehicleStateListeners.end()) {
    1335        11166 :         myVehicleStateListeners.push_back(listener);
    1336              :     }
    1337        11166 : }
    1338              : 
    1339              : 
    1340              : void
    1341           58 : MSNet::removeVehicleStateListener(VehicleStateListener* listener) {
    1342           58 :     std::vector<VehicleStateListener*>::iterator i = std::find(myVehicleStateListeners.begin(), myVehicleStateListeners.end(), listener);
    1343           58 :     if (i != myVehicleStateListeners.end()) {
    1344           58 :         myVehicleStateListeners.erase(i);
    1345              :     }
    1346           58 : }
    1347              : 
    1348              : 
    1349              : void
    1350     16517657 : MSNet::informVehicleStateListener(const SUMOVehicle* const vehicle, VehicleState to, const std::string& info) {
    1351              : #ifdef HAVE_FOX
    1352     16517657 :     ScopedLocker<> lock(myVehicleStateListenerMutex, MSGlobals::gNumThreads > 1);
    1353              : #endif
    1354     17203414 :     for (VehicleStateListener* const listener : myVehicleStateListeners) {
    1355       685757 :         listener->vehicleStateChanged(vehicle, to, info);
    1356              :     }
    1357     16517657 : }
    1358              : 
    1359              : 
    1360              : void
    1361         3890 : MSNet::addTransportableStateListener(TransportableStateListener* listener) {
    1362         3890 :     if (find(myTransportableStateListeners.begin(), myTransportableStateListeners.end(), listener) == myTransportableStateListeners.end()) {
    1363         3890 :         myTransportableStateListeners.push_back(listener);
    1364              :     }
    1365         3890 : }
    1366              : 
    1367              : 
    1368              : void
    1369            0 : MSNet::removeTransportableStateListener(TransportableStateListener* listener) {
    1370            0 :     std::vector<TransportableStateListener*>::iterator i = std::find(myTransportableStateListeners.begin(), myTransportableStateListeners.end(), listener);
    1371            0 :     if (i != myTransportableStateListeners.end()) {
    1372            0 :         myTransportableStateListeners.erase(i);
    1373              :     }
    1374            0 : }
    1375              : 
    1376              : 
    1377              : void
    1378       963348 : MSNet::informTransportableStateListener(const MSTransportable* const transportable, TransportableState to, const std::string& info) {
    1379              : #ifdef HAVE_FOX
    1380       963348 :     ScopedLocker<> lock(myTransportableStateListenerMutex, MSGlobals::gNumThreads > 1);
    1381              : #endif
    1382       965980 :     for (TransportableStateListener* const listener : myTransportableStateListeners) {
    1383         2632 :         listener->transportableStateChanged(transportable, to, info);
    1384              :     }
    1385       963348 : }
    1386              : 
    1387              : 
    1388              : bool
    1389        10824 : MSNet::registerCollision(const SUMOTrafficObject* collider, const SUMOTrafficObject* victim, const std::string& collisionType, const MSLane* lane, double pos) {
    1390              :     auto it = myCollisions.find(collider->getID());
    1391        10824 :     if (it != myCollisions.end()) {
    1392         5128 :         for (Collision& old : it->second) {
    1393         5020 :             if (old.victim == victim->getID()) {
    1394              :                 // collision from previous step continues
    1395         4239 :                 old.continuationTime = myStep;
    1396              :                 return false;
    1397              :             }
    1398              :         }
    1399              :     } else {
    1400              :         // maybe the roles have been reversed
    1401              :         auto it2 = myCollisions.find(victim->getID());
    1402         6477 :         if (it2 != myCollisions.end()) {
    1403          525 :             for (Collision& old : it2->second) {
    1404          364 :                 if (old.victim == collider->getID()) {
    1405              :                     // collision from previous step continues (keep the old roles)
    1406          200 :                     old.continuationTime = myStep;
    1407              :                     return false;
    1408              :                 }
    1409              :             }
    1410              :         }
    1411              :     }
    1412              :     Collision c;
    1413              :     c.victim = victim->getID();
    1414         6385 :     c.colliderType = collider->getVehicleType().getID();
    1415         6385 :     c.victimType = victim->getVehicleType().getID();
    1416         6385 :     c.colliderSpeed = collider->getSpeed();
    1417         6385 :     c.victimSpeed = victim->getSpeed();
    1418         6385 :     c.colliderFront = collider->getPosition();
    1419         6385 :     c.victimFront = victim->getPosition();
    1420         6385 :     c.colliderBack = collider->getPosition(-collider->getVehicleType().getLength());
    1421         6385 :     c.victimBack = victim->getPosition(-victim->getVehicleType().getLength());
    1422              :     c.type = collisionType;
    1423         6385 :     c.lane = lane;
    1424         6385 :     c.pos = pos;
    1425         6385 :     c.time = myStep;
    1426         6385 :     c.continuationTime = myStep;
    1427         6385 :     myCollisions[collider->getID()].push_back(c);
    1428              :     return true;
    1429         6385 : }
    1430              : 
    1431              : 
    1432              : void
    1433     42600684 : MSNet::removeOutdatedCollisions() {
    1434     42615396 :     for (auto it = myCollisions.begin(); it != myCollisions.end();) {
    1435        29644 :         for (auto it2 = it->second.begin(); it2 != it->second.end();) {
    1436        14932 :             if (it2->continuationTime != myStep) {
    1437         6375 :                 it2 = it->second.erase(it2);
    1438              :             } else {
    1439              :                 it2++;
    1440              :             }
    1441              :         }
    1442        14712 :         if (it->second.size() == 0) {
    1443              :             it = myCollisions.erase(it);
    1444              :         } else {
    1445              :             it++;
    1446              :         }
    1447              :     }
    1448     42600684 : }
    1449              : 
    1450              : 
    1451              : bool
    1452        83639 : MSNet::addStoppingPlace(SumoXMLTag category, MSStoppingPlace* stop) {
    1453        83639 :     if (category == SUMO_TAG_TRAIN_STOP) {
    1454        13961 :         category = SUMO_TAG_BUS_STOP;
    1455              :     }
    1456        83639 :     const bool isNew = myStoppingPlaces[category].add(stop->getID(), stop);
    1457        83639 :     if (isNew && stop->getMyName() != "") {
    1458        15959 :         myNamedStoppingPlaces[category][stop->getMyName()].push_back(stop);
    1459              :     }
    1460        83639 :     return isNew;
    1461              : }
    1462              : 
    1463              : 
    1464              : bool
    1465           17 : MSNet::addTractionSubstation(MSTractionSubstation* substation) {
    1466           17 :     if (find(myTractionSubstations.begin(), myTractionSubstations.end(), substation) == myTractionSubstations.end()) {
    1467           17 :         myTractionSubstations.push_back(substation);
    1468           17 :         return true;
    1469              :     }
    1470              :     return false;
    1471              : }
    1472              : 
    1473              : 
    1474              : MSStoppingPlace*
    1475      1775276 : MSNet::getStoppingPlace(const std::string& id, const SumoXMLTag category) const {
    1476              :     if (myStoppingPlaces.count(category) > 0) {
    1477              :         return myStoppingPlaces.find(category)->second.get(id);
    1478              :     }
    1479              :     return nullptr;
    1480              : }
    1481              : 
    1482              : 
    1483              : MSStoppingPlace*
    1484       212287 : MSNet::getStoppingPlace(const std::string& id) const {
    1485      1094170 :     for (SumoXMLTag category : std::vector<SumoXMLTag>({SUMO_TAG_BUS_STOP, SUMO_TAG_PARKING_AREA, SUMO_TAG_CONTAINER_STOP, SUMO_TAG_CHARGING_STATION, SUMO_TAG_OVERHEAD_WIRE_SEGMENT})) {
    1486       918304 :         MSStoppingPlace* result = getStoppingPlace(id, category);
    1487       918304 :         if (result != nullptr) {
    1488              :             return result;
    1489              :         }
    1490       212287 :     }
    1491       175866 :     return nullptr;
    1492              : }
    1493              : 
    1494              : 
    1495              : std::string
    1496       457474 : MSNet::getStoppingPlaceID(const MSLane* lane, const double pos, const SumoXMLTag category) const {
    1497              :     if (myStoppingPlaces.count(category) > 0) {
    1498       918592 :         for (const auto& it : myStoppingPlaces.find(category)->second) {
    1499       844293 :             MSStoppingPlace* stop = it.second;
    1500       844293 :             if (&stop->getLane() == lane && stop->getBeginLanePosition() - POSITION_EPS <= pos && stop->getEndLanePosition() + POSITION_EPS >= pos) {
    1501              :                 return stop->getID();
    1502              :             }
    1503              :         }
    1504              :     }
    1505       353942 :     return "";
    1506              : }
    1507              : 
    1508              : 
    1509              : const std::vector<MSStoppingPlace*>&
    1510         1583 : MSNet::getStoppingPlaceAlternatives(const std::string& name, SumoXMLTag category) const {
    1511         1583 :     if (category == SUMO_TAG_TRAIN_STOP) {
    1512              :         category = SUMO_TAG_BUS_STOP;
    1513              :     }
    1514              :     auto it = myNamedStoppingPlaces.find(category);
    1515         1583 :     if (it != myNamedStoppingPlaces.end()) {
    1516              :         auto it2 = it->second.find(name);
    1517         1515 :         if (it2 != it->second.end()) {
    1518         1515 :             return it2->second;
    1519              :         }
    1520              :     }
    1521              :     return myEmptyStoppingPlaceVector;
    1522              : }
    1523              : 
    1524              : 
    1525              : const NamedObjectCont<MSStoppingPlace*>&
    1526        13997 : MSNet::getStoppingPlaces(SumoXMLTag category) const {
    1527              :     auto it = myStoppingPlaces.find(category);
    1528        13997 :     if (it != myStoppingPlaces.end()) {
    1529        13712 :         return it->second;
    1530              :     } else {
    1531              :         return myEmptyStoppingPlaceCont;
    1532              :     }
    1533              : }
    1534              : 
    1535              : 
    1536              : void
    1537           93 : MSNet::writeChargingStationOutput() const {
    1538              :     if (myStoppingPlaces.count(SUMO_TAG_CHARGING_STATION) > 0) {
    1539          178 :         OutputDevice& output = OutputDevice::getDeviceByOption("chargingstations-output");
    1540          532 :         for (const auto& it : myStoppingPlaces.find(SUMO_TAG_CHARGING_STATION)->second) {
    1541          443 :             static_cast<MSChargingStation*>(it.second)->writeChargingStationOutput(output);
    1542              :         }
    1543              :     }
    1544           93 : }
    1545              : 
    1546              : 
    1547              : void
    1548        39412 : MSNet::writeRailSignalBlocks() const {
    1549        78824 :     if (OptionsCont::getOptions().isSet("railsignal-block-output")) {
    1550         1296 :         OutputDevice& output = OutputDevice::getDeviceByOption("railsignal-block-output");
    1551         5024 :         for (auto tls : myLogics->getAllLogics()) {
    1552         3728 :             MSRailSignal* rs = dynamic_cast<MSRailSignal*>(tls);
    1553         3728 :             if (rs != nullptr) {
    1554         3684 :                 rs->writeBlocks(output, false);
    1555              :             }
    1556         1296 :         }
    1557         1296 :         MSDriveWay::writeDepatureBlocks(output, false);
    1558              :     }
    1559        78824 :     if (OptionsCont::getOptions().isSet("railsignal-vehicle-output")) {
    1560          145 :         OutputDevice& output = OutputDevice::getDeviceByOption("railsignal-vehicle-output");
    1561          489 :         for (auto tls : myLogics->getAllLogics()) {
    1562          344 :             MSRailSignal* rs = dynamic_cast<MSRailSignal*>(tls);
    1563          344 :             if (rs != nullptr) {
    1564          344 :                 rs->writeBlocks(output, true);
    1565              :             }
    1566          145 :         }
    1567          145 :         MSDriveWay::writeDepatureBlocks(output, true);
    1568              :     }
    1569        39412 : }
    1570              : 
    1571              : 
    1572              : void
    1573            5 : MSNet::writeOverheadWireSegmentOutput() const {
    1574              :     if (myStoppingPlaces.count(SUMO_TAG_OVERHEAD_WIRE_SEGMENT) > 0) {
    1575           10 :         OutputDevice& output = OutputDevice::getDeviceByOption("overheadwiresegments-output");
    1576           53 :         for (const auto& it : myStoppingPlaces.find(SUMO_TAG_OVERHEAD_WIRE_SEGMENT)->second) {
    1577           48 :             static_cast<MSOverheadWire*>(it.second)->writeOverheadWireSegmentOutput(output);
    1578              :         }
    1579              :     }
    1580            5 : }
    1581              : 
    1582              : 
    1583              : void
    1584            5 : MSNet::writeSubstationOutput() const {
    1585            5 :     if (myTractionSubstations.size() > 0) {
    1586            5 :         OutputDevice& output = OutputDevice::getDeviceByOption("substations-output");
    1587           10 :         output.setPrecision(OptionsCont::getOptions().getInt("substations-output.precision"));
    1588           13 :         for (auto& it : myTractionSubstations) {
    1589            8 :             it->writeTractionSubstationOutput(output);
    1590              :         }
    1591              :     }
    1592            5 : }
    1593              : 
    1594              : 
    1595              : MSTractionSubstation*
    1596           19 : MSNet::findTractionSubstation(const std::string& substationId) {
    1597           22 :     for (std::vector<MSTractionSubstation*>::iterator it = myTractionSubstations.begin(); it != myTractionSubstations.end(); ++it) {
    1598           22 :         if ((*it)->getID() == substationId) {
    1599              :             return *it;
    1600              :         }
    1601              :     }
    1602              :     return nullptr;
    1603              : }
    1604              : 
    1605              : 
    1606              : MSVehicleRouter&
    1607       122868 : MSNet::getRouterTT(int rngIndex, const Prohibitions& prohibited) const {
    1608       122868 :     if (MSGlobals::gNumSimThreads == 1) {
    1609       104244 :         rngIndex = 0;
    1610              :     }
    1611              :     if (myRouterTT.count(rngIndex) == 0) {
    1612         1354 :         const std::string routingAlgorithm = OptionsCont::getOptions().getString("routing-algorithm");
    1613         1354 :         if (routingAlgorithm == "dijkstra") {
    1614         1268 :             myRouterTT[rngIndex] = new DijkstraRouter<MSEdge, SUMOVehicle>(MSEdge::getAllEdges(), true, &MSNet::getTravelTime, nullptr, false, nullptr, true);
    1615              :         } else {
    1616           86 :             if (routingAlgorithm != "astar") {
    1617            0 :                 WRITE_WARNINGF(TL("TraCI and Triggers cannot use routing algorithm '%'. using 'astar' instead."), routingAlgorithm);
    1618              :             }
    1619           86 :             myRouterTT[rngIndex] = new AStarRouter<MSEdge, SUMOVehicle, MSMapMatcher>(MSEdge::getAllEdges(), true, &MSNet::getTravelTime, nullptr, true);
    1620              :         }
    1621              :     }
    1622       122868 :     myRouterTT[rngIndex]->prohibit(prohibited);
    1623       122868 :     return *myRouterTT[rngIndex];
    1624              : }
    1625              : 
    1626              : 
    1627              : MSVehicleRouter&
    1628           11 : MSNet::getRouterEffort(int rngIndex, const Prohibitions& prohibited) const {
    1629           11 :     if (MSGlobals::gNumSimThreads == 1) {
    1630           11 :         rngIndex = 0;
    1631              :     }
    1632              :     if (myRouterEffort.count(rngIndex) == 0) {
    1633           11 :         myRouterEffort[rngIndex] = new DijkstraRouter<MSEdge, SUMOVehicle>(MSEdge::getAllEdges(), true, &MSNet::getEffort, &MSNet::getTravelTime, false, nullptr, true);
    1634              :     }
    1635           11 :     myRouterEffort[rngIndex]->prohibit(prohibited);
    1636           11 :     return *myRouterEffort[rngIndex];
    1637              : }
    1638              : 
    1639              : 
    1640              : MSPedestrianRouter&
    1641       852474 : MSNet::getPedestrianRouter(int rngIndex, const Prohibitions& prohibited) const {
    1642       852474 :     if (MSGlobals::gNumSimThreads == 1) {
    1643       763703 :         rngIndex = 0;
    1644              :     }
    1645              :     if (myPedestrianRouter.count(rngIndex) == 0) {
    1646         2807 :         myPedestrianRouter[rngIndex] = new MSPedestrianRouter();
    1647              :     }
    1648       852474 :     myPedestrianRouter[rngIndex]->prohibit(prohibited);
    1649       852474 :     return *myPedestrianRouter[rngIndex];
    1650              : }
    1651              : 
    1652              : 
    1653              : MSTransportableRouter&
    1654       208786 : MSNet::getIntermodalRouter(int rngIndex, const int routingMode, const Prohibitions& prohibited) const {
    1655       208786 :     if (MSGlobals::gNumSimThreads == 1) {
    1656              :         rngIndex = 0;
    1657              :     }
    1658       208786 :     const OptionsCont& oc = OptionsCont::getOptions();
    1659       208786 :     const int key = rngIndex * oc.getInt("thread-rngs") + routingMode;
    1660              :     if (myIntermodalRouter.count(key) == 0) {
    1661         4080 :         const int carWalk = SUMOVehicleParserHelper::parseCarWalkTransfer(oc, MSDevice_Taxi::hasFleet() || myInserter->hasTaxiFlow());
    1662         3915 :         const std::string routingAlgorithm = OptionsCont::getOptions().getString("routing-algorithm");
    1663         3915 :         const double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
    1664         3915 :         if (routingMode == libsumo::ROUTING_MODE_COMBINED) {
    1665            0 :             myIntermodalRouter[key] = new MSTransportableRouter(MSNet::adaptIntermodalRouter, carWalk, taxiWait, routingAlgorithm, routingMode, new FareModul());
    1666              :         } else {
    1667         3915 :             myIntermodalRouter[key] = new MSTransportableRouter(MSNet::adaptIntermodalRouter, carWalk, taxiWait, routingAlgorithm, routingMode);
    1668              :         }
    1669              :     }
    1670       208786 :     myIntermodalRouter[key]->prohibit(prohibited);
    1671       208786 :     return *myIntermodalRouter[key];
    1672              : }
    1673              : 
    1674              : 
    1675              : void
    1676         4852 : MSNet::adaptIntermodalRouter(MSTransportableRouter& router) {
    1677         9704 :     double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
    1678              :     // add access to all parking areas
    1679              :     EffortCalculator* const external = router.getExternalEffort();
    1680        14557 :     for (const auto& stopType : myInstance->myStoppingPlaces) {
    1681              :         // add access to all stopping places
    1682         9705 :         const SumoXMLTag element = stopType.first;
    1683        35763 :         for (const auto& i : stopType.second) {
    1684        26058 :             const MSEdge* const edge = &i.second->getLane().getEdge();
    1685        26058 :             router.getNetwork()->addAccess(i.first, edge, i.second->getBeginLanePosition(), i.second->getEndLanePosition(),
    1686              :                                            0., element, false, taxiWait);
    1687        26058 :             if (element == SUMO_TAG_BUS_STOP) {
    1688              :                 // add access to all public transport stops
    1689        12628 :                 for (const auto& a : i.second->getAllAccessPos()) {
    1690         1157 :                     router.getNetwork()->addAccess(i.first, &a.lane->getEdge(), a.startPos, a.endPos, a.length, element, true, taxiWait);
    1691              :                 }
    1692        11471 :                 if (external != nullptr) {
    1693            0 :                     external->addStop(router.getNetwork()->getStopEdge(i.first)->getNumericalID(), *i.second);
    1694              :                 }
    1695              :             }
    1696              :         }
    1697              :     }
    1698         4852 :     myInstance->getInsertionControl().adaptIntermodalRouter(router);
    1699         4852 :     myInstance->getVehicleControl().adaptIntermodalRouter(router);
    1700              :     // add access to transfer from walking to taxi-use
    1701         4852 :     if ((router.getCarWalkTransfer() & ModeChangeOptions::TAXI_PICKUP_ANYWHERE) != 0) {
    1702        59124 :         for (MSEdge* edge : myInstance->getEdgeControl().getEdges()) {
    1703        58895 :             if ((edge->getPermissions() & SVC_PEDESTRIAN) != 0 && (edge->getPermissions() & SVC_TAXI) != 0) {
    1704        21531 :                 router.getNetwork()->addCarAccess(edge, SVC_TAXI, taxiWait);
    1705              :             }
    1706              :         }
    1707              :     }
    1708         4852 : }
    1709              : 
    1710              : 
    1711              : bool
    1712        41045 : MSNet::checkElevation() {
    1713        41045 :     const MSEdgeVector& edges = myEdges->getEdges();
    1714      1752888 :     for (MSEdgeVector::const_iterator e = edges.begin(); e != edges.end(); ++e) {
    1715      3773783 :         for (std::vector<MSLane*>::const_iterator i = (*e)->getLanes().begin(); i != (*e)->getLanes().end(); ++i) {
    1716      2061940 :             if ((*i)->getShape().hasElevation()) {
    1717              :                 return true;
    1718              :             }
    1719              :         }
    1720              :     }
    1721              :     return false;
    1722              : }
    1723              : 
    1724              : 
    1725              : bool
    1726        41045 : MSNet::checkWalkingarea() {
    1727      1276727 :     for (const MSEdge* e : myEdges->getEdges()) {
    1728      1245612 :         if (e->getFunction() == SumoXMLEdgeFunc::WALKINGAREA) {
    1729              :             return true;
    1730              :         }
    1731              :     }
    1732              :     return false;
    1733              : }
    1734              : 
    1735              : 
    1736              : bool
    1737        41045 : MSNet::checkBidiEdges() {
    1738      1695387 :     for (const MSEdge* e : myEdges->getEdges()) {
    1739      1655384 :         if (e->getBidiEdge() != nullptr) {
    1740              :             return true;
    1741              :         }
    1742              :     }
    1743              :     return false;
    1744              : }
    1745              : 
    1746              : bool
    1747          279 : MSNet::warnOnce(const std::string& typeAndID) {
    1748          279 :     if (myWarnedOnce.find(typeAndID) == myWarnedOnce.end()) {
    1749          279 :         myWarnedOnce[typeAndID] = true;
    1750          279 :         return true;
    1751              :     }
    1752              :     return false;
    1753              : }
    1754              : 
    1755              : 
    1756              : MSMapMatcher*
    1757           35 : MSNet::getMapMatcher() const {
    1758           35 :     auto loader = myRouteLoaders->getFirstLoader();
    1759           35 :     if (loader != nullptr) {
    1760           35 :         return dynamic_cast<MSMapMatcher*>(loader->getRouteHandler());
    1761              :     } else {
    1762              :         return nullptr;
    1763              :     }
    1764              : }
    1765              : 
    1766              : void
    1767            0 : MSNet::quickReload() {
    1768            0 :     const OptionsCont& oc = OptionsCont::getOptions();
    1769            0 :     clearState(string2time(oc.getString("begin")), true);
    1770            0 :     NLBuilder::initRandomness();
    1771              :     // load traffic from additional files
    1772            0 :     for (std::string file : oc.getStringVector("additional-files")) {
    1773              :         // ignore failure on parsing calibrator flow
    1774            0 :         MSRouteHandler rh(file, true);
    1775            0 :         const long before = PROGRESS_BEGIN_TIME_MESSAGE("Loading traffic from '" + file + "'");
    1776            0 :         if (!XMLSubSys::runParser(rh, file, false)) {
    1777            0 :             throw ProcessError(TLF("Loading of % failed.", file));
    1778              :         }
    1779            0 :         PROGRESS_TIME_MESSAGE(before);
    1780            0 :     }
    1781            0 :     delete myRouteLoaders;
    1782            0 :     myRouteLoaders = NLBuilder::buildRouteLoaderControl(OptionsCont::getOptions());
    1783            0 :     updateGUI();
    1784            0 : }
    1785              : 
    1786              : 
    1787              : SUMOTime
    1788          178 : MSNet::loadState(const std::string& fileName, const bool catchExceptions) {
    1789              :     // load time only
    1790          178 :     const SUMOTime newTime = MSStateHandler::MSStateTimeHandler::getTime(fileName);
    1791              :     // clean up state
    1792          168 :     clearState(newTime);
    1793              :     // load state
    1794          168 :     MSStateHandler h(fileName, 0);
    1795          168 :     XMLSubSys::runParser(h, fileName, false, false, false, catchExceptions);
    1796          164 :     if (MsgHandler::getErrorInstance()->wasInformed()) {
    1797            0 :         throw ProcessError(TLF("Loading state from '%' failed.", fileName));
    1798              :     }
    1799              :     // reset route loaders
    1800          164 :     delete myRouteLoaders;
    1801          164 :     myRouteLoaders = NLBuilder::buildRouteLoaderControl(OptionsCont::getOptions());
    1802              :     // prevent loading errors on rewound route file
    1803          164 :     MSGlobals::gStateLoaded = true;
    1804              : 
    1805          164 :     updateGUI();
    1806          164 :     return newTime;
    1807          168 : }
    1808              : 
    1809              : 
    1810              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1