LCOV - code coverage report
Current view: top level - src/microsim - MSStateHandler.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 94.8 % 387 367
Test Date: 2026-06-15 15:46:12 Functions: 90.0 % 10 9

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2012-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    MSStateHandler.cpp
      15              : /// @author  Daniel Krajzewicz
      16              : /// @author  Michael Behrisch
      17              : /// @author  Jakob Erdmann
      18              : /// @date    Thu, 13 Dec 2012
      19              : ///
      20              : // Parser and output filter for routes and vehicles state saving and loading
      21              : /****************************************************************************/
      22              : #include <config.h>
      23              : 
      24              : #ifdef HAVE_VERSION_H
      25              : #include <version.h>
      26              : #endif
      27              : 
      28              : #include <sstream>
      29              : #include <utils/common/StringUtils.h>
      30              : #include <utils/options/OptionsCont.h>
      31              : #include <utils/iodevices/OutputDevice.h>
      32              : #include <utils/xml/SUMOXMLDefinitions.h>
      33              : #include <utils/xml/SUMOSAXReader.h>
      34              : #include <utils/xml/XMLSubSys.h>
      35              : #include <utils/vehicle/SUMOVehicleParserHelper.h>
      36              : #include <microsim/traffic_lights/MSTLLogicControl.h>
      37              : #include <microsim/traffic_lights/MSRailSignalConstraint.h>
      38              : #include <microsim/traffic_lights/MSRailSignal.h>
      39              : #include <microsim/traffic_lights/MSDriveWay.h>
      40              : #include <microsim/devices/MSDevice_Routing.h>
      41              : #include <microsim/devices/MSRoutingEngine.h>
      42              : #include <microsim/devices/MSDevice_BTreceiver.h>
      43              : #include <microsim/devices/MSDevice_ToC.h>
      44              : #include <microsim/devices/MSDispatch.h>
      45              : #include <microsim/transportables/MSTransportableControl.h>
      46              : #include <microsim/traffic_lights/MSRailSignalControl.h>
      47              : #include <microsim/output/MSDetectorControl.h>
      48              : #include <microsim/MSEdge.h>
      49              : #include <microsim/MSLane.h>
      50              : #include <microsim/MSLink.h>
      51              : #include <microsim/MSGlobals.h>
      52              : #include <microsim/MSNet.h>
      53              : #include <microsim/MSVehicleTransfer.h>
      54              : #include <microsim/MSInsertionControl.h>
      55              : #include <microsim/MSEdgeControl.h>
      56              : #include <microsim/MSRoute.h>
      57              : #include <microsim/MSVehicleControl.h>
      58              : #include <microsim/MSDriverState.h>
      59              : #include <netload/NLHandler.h>
      60              : #include "MSStateHandler.h"
      61              : 
      62              : #include <mesosim/MESegment.h>
      63              : #include <mesosim/MELoop.h>
      64              : 
      65              : // ===========================================================================
      66              : // MSStateTimeHandler method definitions
      67              : // ===========================================================================
      68              : 
      69              : SUMOTime
      70          486 : MSStateHandler::MSStateTimeHandler::getTime(const std::string& fileName) {
      71              :     // build handler and parser
      72          486 :     MSStateTimeHandler handler;
      73          486 :     handler.setFileName(fileName);
      74          486 :     handler.myTime = -1;
      75          486 :     SUMOSAXReader* parser = XMLSubSys::getSAXReader(handler);
      76              :     try {
      77          960 :         if (!parser->parseFirst(fileName)) {
      78            0 :             delete parser;
      79            0 :             throw ProcessError(TLF("Can not read XML-file '%'.", fileName));
      80              :         }
      81           12 :     } catch (ProcessError&) {
      82           12 :         delete parser;
      83           12 :         throw;
      84           12 :     }
      85              :     // parse
      86        91396 :     while (parser->parseNext() && handler.myTime != -1);
      87              :     // clean up
      88          469 :     if (handler.myTime == -1) {
      89            0 :         delete parser;
      90            0 :         throw ProcessError(TLF("Could not parse time from state file '%'", fileName));
      91              :     }
      92          469 :     delete parser;
      93          469 :     return handler.myTime;
      94              : }
      95              : 
      96              : void
      97        37811 : MSStateHandler::MSStateTimeHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
      98        37811 :     if (element == SUMO_TAG_SNAPSHOT) {
      99          474 :         myTime = string2time(attrs.getString(SUMO_ATTR_TIME));
     100              :     }
     101        37811 : }
     102              : 
     103              : // ===========================================================================
     104              : // method definitions
     105              : // ===========================================================================
     106          468 : MSStateHandler::MSStateHandler(const std::string& file, const SUMOTime offset) :
     107              :     MSRouteHandler(file, true),
     108          468 :     myOffset(offset),
     109          468 :     mySegment(nullptr),
     110          468 :     myCurrentLane(nullptr),
     111          468 :     myCurrentLink(nullptr),
     112          468 :     myAttrs(nullptr),
     113          468 :     myVCAttrs(nullptr),
     114          468 :     myCFMAttrs(nullptr),
     115          468 :     myLastParameterised(nullptr),
     116          468 :     myRemoved(0),
     117          468 :     myFlowIndex(-1),
     118          468 :     myConstrainedSignal(nullptr) {
     119          468 :     myAmLoadingState = true;
     120          936 :     const std::vector<std::string> vehIDs = OptionsCont::getOptions().getStringVector("load-state.remove-vehicles");
     121              :     myVehiclesToRemove.insert(vehIDs.begin(), vehIDs.end());
     122          468 :     myAllowInternalRoutes = true;
     123          468 : }
     124              : 
     125              : 
     126          468 : MSStateHandler::~MSStateHandler() {
     127          468 :     delete myVCAttrs;
     128          468 : }
     129              : 
     130              : 
     131              : void
     132          529 : MSStateHandler::saveState(const std::string& file, SUMOTime step, bool usePrefix) {
     133          529 :     OutputDevice& out = OutputDevice::getDevice(file, usePrefix);
     134          529 :     const int statePrecision = OptionsCont::getOptions().getInt("save-state.precision");
     135          529 :     out.setPrecision(statePrecision);
     136          529 :     const int defaultPrecision = gPrecision;
     137          529 :     gPrecision = statePrecision;
     138              :     std::map<SumoXMLAttr, std::string> attrs;
     139          529 :     attrs[SUMO_ATTR_VERSION] = VERSION_STRING;
     140          529 :     attrs[SUMO_ATTR_TIME] = time2string(step);
     141          877 :     attrs[SUMO_ATTR_TYPE] = MSGlobals::gUseMesoSim ? "meso" : "micro";
     142         1058 :     if (OptionsCont::getOptions().getBool("save-state.constraints")) {
     143           18 :         attrs[SUMO_ATTR_CONSTRAINTS] = "1";
     144              :     }
     145          529 :     if (MSDriveWay::haveDriveWays()) {
     146           48 :         attrs[SUMO_ATTR_RAIL] = "1";
     147              :     }
     148         1058 :     out.writeXMLHeader("snapshot", "state_file.xsd", attrs);
     149         1058 :     if (OptionsCont::getOptions().getBool("save-state.rng")) {
     150           45 :         saveRNGs(out);
     151           45 :         if (!MSGlobals::gUseMesoSim) {
     152           30 :             MSNet::getInstance()->getEdgeControl().saveState(out);
     153              :         }
     154              :     }
     155              :     const MSDispatch* dispatcher = MSDevice_Taxi::getDispatchAlgorithm();
     156          529 :     if (dispatcher != nullptr) {
     157              :         // save early to pre-empty initialization from loaded persons
     158           16 :         dispatcher->saveState(out, MSDevice_Taxi::getNextDispatchTime());
     159              :     }
     160          529 :     MSRoute::dict_saveState(out);
     161          529 :     MSNet::getInstance()->getVehicleControl().saveState(out);
     162          529 :     MSNet::getInstance()->getInsertionControl().saveState(out);
     163         1058 :     if (OptionsCont::getOptions().getBool("save-state.transportables")) {
     164           53 :         if (MSNet::getInstance()->hasPersons()) {
     165           53 :             out.openTag(SUMO_TAG_TRANSPORTABLES).writeAttr(SUMO_ATTR_TYPE, "person");
     166           53 :             MSNet::getInstance()->getPersonControl().saveState(out);
     167          106 :             out.closeTag();
     168              :         }
     169           53 :         if (MSNet::getInstance()->hasContainers()) {
     170            0 :             out.openTag(SUMO_TAG_TRANSPORTABLES).writeAttr(SUMO_ATTR_TYPE, "container");
     171            0 :             MSNet::getInstance()->getContainerControl().saveState(out);
     172            0 :             out.closeTag();
     173              :         }
     174              :     }
     175          529 :     MSVehicleTransfer::getInstance()->saveState(out);
     176        18170 :     for (MSEdge* const edge : MSEdge::getAllEdges()) {
     177        17641 :         if (MSGlobals::gUseMesoSim) {
     178        24558 :             for (MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*edge); s != nullptr; s = s->getNextSegment()) {
     179        12140 :                 s->saveState(out);
     180              :             }
     181              :         } else {
     182        23978 :             for (MSLane* const lane : edge->getLanes()) {
     183        12546 :                 lane->saveState(out);
     184              :             }
     185              :         }
     186              :     }
     187          529 :     MSNet::getInstance()->getTLSControl().saveState(out);
     188          529 :     MSRoutingEngine::saveState(out);
     189          529 :     out.close();
     190          529 :     gPrecision = defaultPrecision;
     191          529 : }
     192              : 
     193              : 
     194              : void
     195        37318 : MSStateHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
     196        37318 :     MSRouteHandler::myStartElement(element, attrs);
     197        37316 :     MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
     198        37316 :     switch (element) {
     199          468 :         case SUMO_TAG_SNAPSHOT: {
     200          468 :             myTime = string2time(attrs.getString(SUMO_ATTR_TIME));
     201          468 :             const std::string& version = attrs.getString(SUMO_ATTR_VERSION);
     202          468 :             if (version != VERSION_STRING) {
     203          477 :                 WRITE_WARNINGF(TL("State was written with sumo version % (present: %)!"), version, VERSION_STRING);
     204              :             }
     205              :             bool ok;
     206          468 :             if (attrs.getOpt<bool>(SUMO_ATTR_CONSTRAINTS, nullptr, ok, false)) {
     207            7 :                 MSRailSignalConstraint::clearAll();
     208              :             }
     209          468 :             if (attrs.getOpt<bool>(SUMO_ATTR_RAIL, nullptr, ok, false)) {
     210              :                 // init before loading any vehicles to ensure that driveways are built early
     211           23 :                 MSRailSignalControl::getInstance();
     212              :             }
     213              :             break;
     214              :         }
     215           45 :         case SUMO_TAG_RNGSTATE: {
     216           45 :             if (attrs.hasAttribute(SUMO_ATTR_DEFAULT)) {
     217           90 :                 RandHelper::loadState(attrs.getString(SUMO_ATTR_DEFAULT));
     218              :             }
     219           45 :             if (attrs.hasAttribute(SUMO_ATTR_RNG_ROUTEHANDLER)) {
     220           90 :                 RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_ROUTEHANDLER), MSRouteHandler::getParsingRNG());
     221              :             }
     222           45 :             if (attrs.hasAttribute(SUMO_ATTR_RNG_INSERTIONCONTROL)) {
     223           90 :                 RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_INSERTIONCONTROL), MSNet::getInstance()->getInsertionControl().getFlowRNG());
     224              :             }
     225           45 :             if (attrs.hasAttribute(SUMO_ATTR_RNG_DEVICE)) {
     226           90 :                 RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DEVICE), MSDevice::getEquipmentRNG());
     227              :             }
     228           45 :             if (attrs.hasAttribute(SUMO_ATTR_RNG_DEVICE_BT)) {
     229           90 :                 RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DEVICE_BT), MSDevice_BTreceiver::getRNG());
     230              :             }
     231           45 :             if (attrs.hasAttribute(SUMO_ATTR_RNG_DRIVERSTATE)) {
     232           90 :                 RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DRIVERSTATE), OUProcess::getRNG());
     233              :             }
     234           45 :             if (attrs.hasAttribute(SUMO_ATTR_RNG_DEVICE_TOC)) {
     235           90 :                 RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DEVICE_TOC), MSDevice_ToC::getResponseTimeRNG());
     236              :             }
     237              :             break;
     238              :         }
     239         2880 :         case SUMO_TAG_RNGLANE: {
     240         2880 :             const int index = attrs.getInt(SUMO_ATTR_INDEX);
     241         2880 :             const std::string state = attrs.getString(SUMO_ATTR_STATE);
     242         2880 :             MSLane::loadRNGState(index, state);
     243              :             break;
     244              :         }
     245              :         case SUMO_TAG_EDGECONTROL: {
     246              :             bool ok;
     247              :             std::list<MSLane*> activeLanes;
     248           30 :             const std::vector<std::string>& laneIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_LANES, nullptr, ok, false);
     249           94 :             for (const std::string& laneID : laneIDs) {
     250           64 :                 MSLane* lane = MSLane::dictionary(laneID);
     251           64 :                 if (lane == nullptr) {
     252            0 :                     throw ProcessError(TLF("Unknown lane '%' in loaded state.", laneID));
     253              :                 }
     254              :                 activeLanes.push_back(lane);
     255              :             }
     256           30 :             MSNet::getInstance()->getEdgeControl().setActiveLanes(activeLanes);
     257              :             break;
     258           30 :         }
     259          191 :         case SUMO_TAG_ROUTINGENGINE: {
     260          191 :             bool ok = true;
     261          191 :             const SUMOTime lastAdaptation = attrs.get<SUMOTime>(SUMO_ATTR_LAST, nullptr, ok);
     262          191 :             const int index = attrs.get<int>(SUMO_ATTR_INDEX, nullptr, ok);
     263          191 :             if (lastAdaptation >= 0) {
     264          191 :                 MSRoutingEngine::initWeightUpdate(lastAdaptation);
     265              :             }
     266          191 :             MSRoutingEngine::initEdgeWeights(SVC_PASSENGER, lastAdaptation, index);
     267          382 :             if (OptionsCont::getOptions().getBool("device.rerouting.bike-speeds")) {
     268            0 :                 MSRoutingEngine::initEdgeWeights(SVC_BICYCLE);
     269              :             }
     270          191 :             if (MSGlobals::gUseMesoSim) {
     271         3712 :                 for (const MSEdge* e : MSEdge::getAllEdges()) {
     272         9256 :                     for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*e); segment != nullptr; segment = segment->getNextSegment()) {
     273         5582 :                         segment->resetCachedSpeeds();
     274              :                     }
     275              :                 }
     276              :             }
     277              :             break;
     278              :         }
     279         1823 :         case SUMO_TAG_EDGE: {
     280              : #ifdef HAVE_FOX
     281         1823 :             MSRoutingEngine::loadState(attrs);
     282              : #endif
     283         1823 :             break;
     284              :         }
     285          466 :         case SUMO_TAG_DELAY: {
     286          466 :             if (myVCAttrs != nullptr) {
     287            0 :                 delete myVCAttrs;
     288              :             }
     289              :             bool ok;
     290          466 :             MSNet::getInstance()->setLoaderTime(attrs.getOpt<SUMOTime>(SUMO_ATTR_LOADERTIME, nullptr, ok, 0));
     291          466 :             myVCAttrs = attrs.clone();
     292              :             break;
     293              :         }
     294           62 :         case SUMO_TAG_FLOWSTATE: {
     295              :             bool ok;
     296           62 :             SUMOVehicleParameter* pars = SUMOVehicleParserHelper::parseFlowAttributes(SUMO_TAG_FLOWSTATE, attrs, true, true, -1, -1, true);
     297           62 :             pars->repetitionsDone = attrs.get<int>(SUMO_ATTR_DONE, pars->id.c_str(), ok);
     298           62 :             pars->repetitionTotalOffset = attrs.getOptSUMOTimeReporting(SUMO_ATTR_NEXT, pars->id.c_str(), ok, 0);
     299           62 :             myFlowIndex = attrs.getInt(SUMO_ATTR_INDEX);
     300           62 :             myVehicleParameter = pars;
     301              :             break;
     302              :         }
     303          717 :         case SUMO_TAG_VTYPE: {
     304          717 :             myLastParameterised = myCurrentVType;
     305          717 :             break;
     306              :         }
     307         4924 :         case SUMO_TAG_VEHICLE: {
     308         4924 :             myLastParameterised = myVehicleParameter;
     309         4924 :             myAttrs = attrs.clone();
     310         4924 :             break;
     311              :         }
     312         6699 :         case SUMO_TAG_DEVICE: {
     313         6699 :             myDeviceAttrs.push_back(attrs.clone());
     314         6699 :             break;
     315              :         }
     316           90 :         case SUMO_TAG_CFM_VARIABLES: {
     317           90 :             myCFMAttrs = attrs.clone();
     318           90 :             break;
     319              :         }
     320          182 :         case SUMO_TAG_REMINDER: {
     321          182 :             myReminderAttrs.push_back(attrs.clone());
     322          182 :             break;
     323              :         }
     324          205 :         case SUMO_TAG_VEHICLETRANSFER: {
     325          205 :             MSVehicleTransfer::getInstance()->loadState(attrs, myOffset, vc);
     326          205 :             break;
     327              :         }
     328         1107 :         case SUMO_TAG_SEGMENT: {
     329         1107 :             const std::string& segmentID = attrs.getString(SUMO_ATTR_ID);
     330         2214 :             const MSEdge* const edge = MSEdge::dictionary(segmentID.substr(0, segmentID.rfind(":")));
     331         1107 :             int idx = StringUtils::toInt(segmentID.substr(segmentID.rfind(":") + 1));
     332         1107 :             mySegment = MSGlobals::gMesoNet->getSegmentForEdge(*edge);
     333         1601 :             while (idx-- > 0 && mySegment != nullptr) {
     334          494 :                 mySegment = mySegment->getNextSegment();
     335              :             }
     336         1107 :             if (mySegment == nullptr) {
     337            0 :                 throw ProcessError(TLF("Unknown segment '%' in loaded state.", segmentID));
     338              :             }
     339         1107 :             myQueIndex = 0;
     340              :             break;
     341              :         }
     342          600 :         case SUMO_TAG_LANE: {
     343              :             bool ok;
     344          600 :             const std::string laneID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     345          600 :             myCurrentLane = MSLane::dictionary(laneID);
     346          600 :             if (myCurrentLane == nullptr) {
     347            0 :                 throw ProcessError(TLF("Unknown lane '%' in loaded state.", laneID));
     348              :             }
     349              :             break;
     350              :         }
     351         1747 :         case SUMO_TAG_VIEWSETTINGS_VEHICLES: {
     352              :             bool ok;
     353         1747 :             const std::vector<std::string>& vehIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_VALUE, nullptr, ok, false);
     354              :             std::vector<SUMOVehicle*> vehs;
     355         3711 :             for (const std::string& id : vehIDs) {
     356         1964 :                 SUMOVehicle* v = vc.getVehicle(id);
     357              :                 // vehicle could be removed due to options
     358         1964 :                 if (v != nullptr) {
     359         1956 :                     vehs.push_back(v);
     360              :                     myArrived.erase(v);
     361              :                 }
     362              :             }
     363         1747 :             if (MSGlobals::gUseMesoSim) {
     364         1165 :                 if (myQueIndex >= mySegment->numQueues()) {
     365            3 :                     throw ProcessError(TLF("Invalid queue index '%' on segment '%'. Check for consistency of lane numbers and queue options.", myQueIndex, mySegment->getID()));
     366              :                 }
     367         1164 :                 const SUMOTime blockTime = StringUtils::toLong(attrs.getString(SUMO_ATTR_TIME));
     368         1164 :                 const SUMOTime entryBlockTime = StringUtils::toLong(attrs.getString(SUMO_ATTR_BLOCKTIME));
     369         1164 :                 mySegment->loadState(vehs, blockTime - myOffset, entryBlockTime - myOffset, myQueIndex);
     370         1164 :                 myQueIndex++;
     371              :             } else {
     372          582 :                 myCurrentLane->loadState(vehs);
     373              :             }
     374              :             break;
     375         1748 :         }
     376           32 :         case SUMO_TAG_LINK: {
     377              :             bool ok;
     378           32 :             myCurrentLink = nullptr;
     379           32 :             const std::string toLaneID = attrs.get<std::string>(SUMO_ATTR_TO, nullptr, ok);
     380           67 :             for (MSLink* link : myCurrentLane->getLinkCont()) {
     381           35 :                 if (link->getViaLaneOrLane()->getID() == toLaneID) {
     382           32 :                     myCurrentLink = link;
     383              :                 }
     384              :             }
     385           32 :             if (myCurrentLink == nullptr) {
     386            0 :                 throw ProcessError("Unknown link from lane '" + myCurrentLane->getID() + "' to lane '" + toLaneID + "' in loaded state");
     387              :             }
     388              :             break;
     389              :         }
     390           32 :         case SUMO_TAG_APPROACHING: {
     391              :             bool ok;
     392           32 :             const std::string vehID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     393           32 :             const SUMOTime arrivalTime = attrs.get<SUMOTime>(SUMO_ATTR_ARRIVALTIME, nullptr, ok);
     394           32 :             const double arrivalSpeed = attrs.get<double>(SUMO_ATTR_ARRIVALSPEED, nullptr, ok);
     395           32 :             const double leaveSpeed = attrs.get<double>(SUMO_ATTR_DEPARTSPEED, nullptr, ok);
     396           32 :             const bool setRequest = attrs.get<bool>(SUMO_ATTR_REQUEST, nullptr, ok);
     397           32 :             const double arrivalSpeedBraking = attrs.get<double>(SUMO_ATTR_ARRIVALSPEEDBRAKING, nullptr, ok);
     398           32 :             const SUMOTime waitingTime = attrs.get<SUMOTime>(SUMO_ATTR_WAITINGTIME, nullptr, ok);
     399           32 :             const double dist = attrs.get<double>(SUMO_ATTR_DISTANCE, nullptr, ok);
     400           32 :             const double latOffset = attrs.getOpt<double>(SUMO_ATTR_POSITION_LAT, nullptr, ok, 0);
     401           32 :             SUMOVehicle* veh = vc.getVehicle(vehID);
     402           32 :             myCurrentLink->setApproaching(veh, arrivalTime, arrivalSpeed, leaveSpeed, setRequest, arrivalSpeedBraking, waitingTime, dist, latOffset);
     403           32 :             if (!MSGlobals::gUseMesoSim) {
     404           32 :                 MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
     405           32 :                 microVeh->loadPreviousApproaching(myCurrentLink, setRequest, arrivalTime, arrivalSpeed, arrivalSpeedBraking, dist, leaveSpeed);
     406              :             }
     407              :             break;
     408              :         }
     409            4 :         case SUMO_TAG_RAILSIGNAL_CONSTRAINT_TRACKER: {
     410            4 :             MSRailSignalConstraint_Predecessor::loadState(attrs);
     411            4 :             break;
     412              :         }
     413           43 :         case SUMO_TAG_DRIVEWAY:
     414              :         case SUMO_TAG_SUBDRIVEWAY: {
     415           43 :             MSDriveWay::loadState(attrs, element);
     416           43 :             break;
     417              :         }
     418          163 :         case SUMO_TAG_PARAM: {
     419              :             bool ok;
     420          163 :             const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
     421              :             // circumventing empty string test
     422          163 :             const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
     423              :             assert(myLastParameterised != 0);
     424          163 :             if (myLastParameterised != nullptr) {
     425          163 :                 myLastParameterised->setParameter(key, val);
     426              :             }
     427              :             break;
     428              :         }
     429           57 :         case SUMO_TAG_TRANSPORTABLES:
     430           57 :             if (attrs.getString(SUMO_ATTR_TYPE) == "person") {
     431          114 :                 MSNet::getInstance()->getPersonControl().loadState(attrs.getString(SUMO_ATTR_STATE));
     432              :             }
     433           57 :             if (attrs.getString(SUMO_ATTR_TYPE) == "container") {
     434            0 :                 MSNet::getInstance()->getContainerControl().loadState(attrs.getString(SUMO_ATTR_STATE));
     435              :             }
     436              :             break;
     437          219 :         case SUMO_TAG_PERSON:
     438              :         case SUMO_TAG_CONTAINER:
     439          219 :             myAttrs = attrs.clone();
     440          219 :             break;
     441           17 :         case SUMO_TAG_RAILSIGNAL_CONSTRAINTS: {
     442           17 :             bool ok = true;
     443           17 :             const std::string signalID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     444           17 :             if (!MSNet::getInstance()->getTLSControl().knows(signalID)) {
     445            0 :                 throw InvalidArgument("Rail signal '" + signalID + "' in railSignalConstraints loaded from state is not known");
     446              :             }
     447           17 :             myConstrainedSignal = dynamic_cast<MSRailSignal*>(MSNet::getInstance()->getTLSControl().get(signalID).getDefault());
     448           17 :             if (myConstrainedSignal == nullptr) {
     449            0 :                 throw InvalidArgument("Traffic light '" + signalID + "' is not a rail signal");
     450              :             }
     451              :             break;
     452              :         }
     453           25 :         case SUMO_TAG_PREDECESSOR: // intended fall-through
     454              :         case SUMO_TAG_INSERTION_PREDECESSOR: // intended fall-through
     455              :         case SUMO_TAG_FOE_INSERTION: // intended fall-through
     456              :         case SUMO_TAG_INSERTION_ORDER: // intended fall-through
     457              :         case SUMO_TAG_BIDI_PREDECESSOR:
     458           25 :             myLastParameterised = NLHandler::addPredecessorConstraint(element, attrs, myConstrainedSignal);
     459           25 :             break;
     460         1946 :         case SUMO_TAG_TLLOGIC: {
     461              :             bool ok;
     462         1946 :             const std::string tlID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
     463         1946 :             const std::string programID = attrs.get<std::string>(SUMO_ATTR_PROGRAMID, tlID.c_str(), ok);
     464         1946 :             const int phase = attrs.get<int>(SUMO_ATTR_PHASE, tlID.c_str(), ok);
     465         1946 :             const SUMOTime spentDuration = attrs.get<SUMOTime>(SUMO_ATTR_DURATION, tlID.c_str(), ok);
     466         1946 :             const bool active = attrs.get<bool>(SUMO_ATTR_ACTIVE, tlID.c_str(), ok);
     467         1946 :             MSTLLogicControl& tlc = MSNet::getInstance()->getTLSControl();
     468         1946 :             MSTrafficLightLogic* tl = tlc.get(tlID, programID);
     469         1946 :             if (tl == nullptr) {
     470            8 :                 if (programID == "online") {
     471           24 :                     WRITE_WARNINGF(TL("Ignoring program '%' for traffic light '%' in loaded state"), programID, tlID);
     472              :                     return;
     473              :                 } else {
     474            0 :                     throw ProcessError("Unknown program '" + programID + "' for traffic light '" + tlID + "'");
     475              :                 }
     476              :             }
     477         1938 :             if (phase >= tl->getPhaseNumber()) {
     478            0 :                 throw ProcessError("Invalid phase '" + toString(phase) + "' for traffic light '" + tlID + "'");
     479              :             }
     480              :             // might not be set if the phase happens to match and there are multiple programs
     481         1938 :             tl->loadState(tlc, myTime, phase, spentDuration, active);
     482         1938 :             if (attrs.hasAttribute(SUMO_ATTR_STATE)) {
     483            2 :                 tl->loadExtraState(attrs.get<std::string>(SUMO_ATTR_STATE, tlID.c_str(), ok));
     484              :             }
     485              :             break;
     486              :         }
     487           16 :         case SUMO_TAG_DISPATCHER: {
     488           16 :             bool ok = true;
     489           16 :             SUMOTime next = attrs.get<SUMOTime>(SUMO_ATTR_NEXT, "dispatcher", ok);
     490           16 :             MSDevice_Taxi::initDispatch(next);
     491           16 :             MSDevice_Taxi::getDispatchAlgorithm()->loadState(attrs);
     492              :             break;
     493              :         }
     494              :         default:
     495              :             break;
     496              :     }
     497              : }
     498              : 
     499              : 
     500              : void
     501        37304 : MSStateHandler::myEndElement(int element) {
     502        37304 :     MSRouteHandler::myEndElement(element);
     503        37297 :     switch (element) {
     504          219 :         case SUMO_TAG_PERSON:
     505              :         case SUMO_TAG_CONTAINER: {
     506          219 :             MSTransportableControl& tc = (element == SUMO_TAG_PERSON ? MSNet::getInstance()->getPersonControl() : MSNet::getInstance()->getContainerControl());
     507          219 :             MSTransportable* transportable = tc.get(myAttrs->getString(SUMO_ATTR_ID));
     508          219 :             transportable->loadState(myAttrs->getString(SUMO_ATTR_STATE));
     509          219 :             tc.fixLoadCount(transportable);
     510          219 :             delete myAttrs;
     511          219 :             myAttrs = nullptr;
     512          219 :             break;
     513              :         }
     514           62 :         case SUMO_TAG_FLOWSTATE: {
     515           62 :             MSNet::getInstance()->getInsertionControl().addFlow(myVehicleParameter, myFlowIndex);
     516           62 :             myVehicleParameter = nullptr;
     517           62 :             break;
     518              :         }
     519          458 :         case SUMO_TAG_SNAPSHOT: {
     520          458 :             if (myVCAttrs == nullptr) {
     521            0 :                 throw ProcessError(TL("Could not load vehicle control state"));
     522              :             }
     523          458 :             MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
     524          458 :             vc.setState(myVCAttrs->getInt(SUMO_ATTR_NUMBER),
     525          458 :                         myVCAttrs->getInt(SUMO_ATTR_BEGIN),
     526          458 :                         myVCAttrs->getInt(SUMO_ATTR_END),
     527          458 :                         myVCAttrs->getFloat(SUMO_ATTR_DEPART),
     528          458 :                         myVCAttrs->getFloat(SUMO_ATTR_TIME),
     529          458 :                         myVCAttrs->getFloat(SUMO_ATTR_SPEEDFACTOR),
     530          458 :                         myVCAttrs->getFloat(SUMO_ATTR_DECEL));
     531          458 :             if (myRemoved > 0) {
     532           16 :                 WRITE_MESSAGEF(TL("Removed % vehicles while loading state."), toString(myRemoved));
     533            8 :                 vc.discountStateRemoved(myRemoved);
     534              :             }
     535          461 :             for (SUMOVehicle* v : myArrived) {
     536              :                 // state was created with active option --keep-after-arrival
     537            3 :                 vc.deleteKeptVehicle(v);
     538              :             }
     539          458 :             if (!MSGlobals::gUseMesoSim) {
     540         3804 :                 for (MSVehicleControl::constVehIt i = vc.loadedVehBegin(); i != vc.loadedVehEnd(); ++i) {
     541         3472 :                     MSVehicle* microVeh = dynamic_cast<MSVehicle*>((*i).second);
     542         3472 :                     if (microVeh->hasDeparted() && microVeh->getLane() != nullptr) {
     543              :                         // occupancy update must happen after all lane states have been loaded
     544         1667 :                         microVeh->updateBestLanes();
     545              :                     }
     546              :                 }
     547              :             }
     548          458 :             MSDevice_Taxi::finalizeLoadState();
     549          458 :             break;
     550              :         }
     551              :         default:
     552              :             break;
     553              :     }
     554        37297 :     if (element != SUMO_TAG_PARAM && myVehicleParameter == nullptr && myCurrentVType == nullptr) {
     555        22973 :         myLastParameterised = nullptr;
     556              :     }
     557        37297 : }
     558              : 
     559              : 
     560              : void
     561         4924 : MSStateHandler::closeVehicle() {
     562              :     assert(myVehicleParameter != nullptr);
     563         4924 :     myVehicleParameter->depart -= myOffset;
     564              :     // the vehicle was already counted in MSVehicleControl::setState
     565         4924 :     MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
     566              :     // make a copy because myVehicleParameter is reset in closeVehicle()
     567         4924 :     const std::string vehID = myVehicleParameter->id;
     568              :     if (myVehiclesToRemove.count(vehID) == 0) {
     569              : 
     570              :         // devices that influence simulation behavior must replicate stochastic assignment
     571              :         // also, setting the parameter avoids extra calls to MSDevice::myEquipmentRNG (which would pollute replication)
     572              :         std::vector<std::string> deviceNames;
     573        11607 :         for (auto attrs : myDeviceAttrs) {
     574        13382 :             deviceNames.push_back(MSDevice::getDeviceName(attrs->getString(SUMO_ATTR_ID)));
     575              :         }
     576         4916 :         myVehicleParameter->setParameter(MSDevice::LOADSTATE_DEVICENAMES, toString(deviceNames));
     577         4916 :         MSRouteHandler::closeVehicle();
     578         4915 :         SUMOVehicle* v = vc.getVehicle(vehID);
     579              :         // special case: transportable devices are not assigned by options
     580         4915 :         if (std::find(deviceNames.begin(), deviceNames.end(), "person") != deviceNames.end()) {
     581           27 :             dynamic_cast<MSBaseVehicle*>(v)->initTransportableDevice(true);
     582              :         }
     583         4915 :         if (std::find(deviceNames.begin(), deviceNames.end(), "container") != deviceNames.end()) {
     584            0 :             dynamic_cast<MSBaseVehicle*>(v)->initTransportableDevice(false);
     585              :         }
     586              :         // clean up added param after initializing devices in closeVehicle
     587         4915 :         ((SUMOVehicleParameter&)v->getParameter()).unsetParameter(MSDevice::LOADSTATE_DEVICENAMES);
     588              :         if (v == nullptr) {
     589              :             throw ProcessError(TLF("Could not load vehicle '%' from state", vehID));
     590              :         }
     591         4915 :         v->setChosenSpeedFactor(myAttrs->getFloat(SUMO_ATTR_SPEEDFACTOR));
     592         4915 :         v->loadState(*myAttrs, myOffset);
     593              : 
     594         4909 :         if (v->hasDeparted()) {
     595              :             // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
     596         2430 :             MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(v->getDevice(typeid(MSDevice_Routing)));
     597              :             if (routingDevice != nullptr) {
     598         1722 :                 routingDevice->notifyEnter(*v, MSMoveReminder::NOTIFICATION_DEPARTED);
     599              :             }
     600         2430 :             MSNet::getInstance()->getInsertionControl().alreadyDeparted(v);
     601         2430 :             if (MSRailSignalControl::hasInstance()) {
     602              :                 // register route for deadlock prevention (vehicleStateChanged would not be called otherwise)
     603           68 :                 MSRailSignalControl::getInstance().vehicleStateChanged(v, MSNet::VehicleState::NEWROUTE, "loadState");
     604              :             }
     605         2430 :             vc.handleTriggeredDepart(v, false);
     606         2430 :             if (v->hasArrived()) {
     607              :                 myArrived.insert(v);
     608              :             }
     609              :         }
     610        11593 :         while (!myDeviceAttrs.empty()) {
     611         6684 :             const std::string attrID = myDeviceAttrs.back()->getString(SUMO_ATTR_ID);
     612        18085 :             for (MSVehicleDevice* const dev : v->getDevices()) {
     613        11401 :                 if (dev->getID() == attrID) {
     614         6683 :                     dev->loadState(*myDeviceAttrs.back());
     615              :                 }
     616              :             }
     617         6684 :             delete myDeviceAttrs.back();
     618              :             myDeviceAttrs.pop_back();
     619              :         }
     620         4909 :         bool ok = true;
     621         5088 :         while (!myReminderAttrs.empty()) {
     622          179 :             const std::string attrID = myReminderAttrs.back()->getString(SUMO_ATTR_ID);
     623          179 :             const SUMOTime time = myReminderAttrs.back()->get<SUMOTime>(SUMO_ATTR_TIME, nullptr, ok, false);
     624          179 :             const double pos = myReminderAttrs.back()->get<double>(SUMO_ATTR_POSITION, nullptr, ok, false);
     625          179 :             const auto& remDict = MSNet::getInstance()->getDetectorControl().getAllReminders();
     626              :             auto it = remDict.find(attrID);
     627          179 :             if (it != remDict.end()) {
     628            6 :                 it->second->loadReminderState(v->getNumericalID(), time, pos);
     629              :             }
     630          179 :             delete myReminderAttrs.back();
     631              :             myReminderAttrs.pop_back();
     632              :         }
     633         4909 :         if (myCFMAttrs != nullptr) {
     634              :             assert(!MSGlobals::gUseMesoSim);
     635           90 :             MSVehicle* microVeh = dynamic_cast<MSVehicle*>(v);
     636              :             const MSCFModel::VehicleVariables* vars = microVeh->getCarFollowVariables();
     637           90 :             if (vars != nullptr) {
     638           90 :                 const_cast<MSCFModel::VehicleVariables*>(vars)->loadState(*myCFMAttrs);
     639              :             }
     640           90 :             delete myCFMAttrs;
     641           90 :             myCFMAttrs = nullptr;
     642              :         }
     643         4916 :     } else {
     644            8 :         const std::string embeddedRouteID = "!" + myVehicleParameter->id;
     645            8 :         if (MSRoute::hasRoute(embeddedRouteID)) {
     646            2 :             ConstMSRoutePtr embedded = MSRoute::dictionary(embeddedRouteID);
     647            2 :             embedded->checkRemoval();
     648              :         }
     649            8 :         delete myVehicleParameter;
     650              : 
     651            8 :         myVehicleParameter = nullptr;
     652            8 :         myRemoved++;
     653           16 :         while (!myDeviceAttrs.empty()) {
     654            8 :             delete myDeviceAttrs.back();
     655              :             myDeviceAttrs.pop_back();
     656              :         }
     657            9 :         while (!myReminderAttrs.empty()) {
     658            1 :             delete myReminderAttrs.back();
     659              :             myReminderAttrs.pop_back();
     660              :         }
     661              :     }
     662         4917 :     delete myAttrs;
     663         4917 : }
     664              : 
     665              : 
     666              : void
     667           45 : MSStateHandler::saveRNGs(OutputDevice& out) {
     668           45 :     out.openTag(SUMO_TAG_RNGSTATE);
     669           45 :     out.writeAttr(SUMO_ATTR_DEFAULT, RandHelper::saveState());
     670           45 :     out.writeAttr(SUMO_ATTR_RNG_ROUTEHANDLER, RandHelper::saveState(MSRouteHandler::getParsingRNG()));
     671           45 :     out.writeAttr(SUMO_ATTR_RNG_INSERTIONCONTROL, RandHelper::saveState(MSNet::getInstance()->getInsertionControl().getFlowRNG()));
     672           45 :     out.writeAttr(SUMO_ATTR_RNG_DEVICE, RandHelper::saveState(MSDevice::getEquipmentRNG()));
     673           45 :     out.writeAttr(SUMO_ATTR_RNG_DEVICE_BT, RandHelper::saveState(MSDevice_BTreceiver::getRNG()));
     674           45 :     out.writeAttr(SUMO_ATTR_RNG_DRIVERSTATE, RandHelper::saveState(OUProcess::getRNG()));
     675           45 :     out.writeAttr(SUMO_ATTR_RNG_DEVICE_TOC, RandHelper::saveState(MSDevice_ToC::getResponseTimeRNG()));
     676           45 :     MSLane::saveRNGStates(out);
     677           45 :     out.closeTag();
     678              : 
     679           45 : }
     680              : 
     681              : 
     682              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1