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

Generated by: LCOV version 2.0-1