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

Generated by: LCOV version 2.0-1