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 450 : MSStateHandler::MSStateTimeHandler::getTime(const std::string& fileName) {
70 : // build handler and parser
71 450 : MSStateTimeHandler handler;
72 450 : handler.setFileName(fileName);
73 450 : handler.myTime = -1;
74 450 : SUMOSAXReader* parser = XMLSubSys::getSAXReader(handler);
75 : try {
76 889 : 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 82187 : while (parser->parseNext() && handler.myTime != -1);
86 : // clean up
87 434 : if (handler.myTime == -1) {
88 0 : delete parser;
89 0 : throw ProcessError(TLF("Could not parse time from state file '%'", fileName));
90 : }
91 434 : delete parser;
92 434 : return handler.myTime;
93 : }
94 :
95 : void
96 33677 : MSStateHandler::MSStateTimeHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
97 33677 : if (element == SUMO_TAG_SNAPSHOT) {
98 439 : myTime = string2time(attrs.getString(SUMO_ATTR_TIME));
99 : }
100 33677 : }
101 :
102 : // ===========================================================================
103 : // method definitions
104 : // ===========================================================================
105 432 : MSStateHandler::MSStateHandler(const std::string& file, const SUMOTime offset) :
106 : MSRouteHandler(file, true),
107 432 : myOffset(offset),
108 432 : mySegment(nullptr),
109 432 : myCurrentLane(nullptr),
110 432 : myCurrentLink(nullptr),
111 432 : myAttrs(nullptr),
112 432 : myVCAttrs(nullptr),
113 432 : myLastParameterised(nullptr),
114 432 : myRemoved(0),
115 432 : myFlowIndex(-1),
116 432 : myConstrainedSignal(nullptr) {
117 432 : myAmLoadingState = true;
118 864 : const std::vector<std::string> vehIDs = OptionsCont::getOptions().getStringVector("load-state.remove-vehicles");
119 : myVehiclesToRemove.insert(vehIDs.begin(), vehIDs.end());
120 432 : myAllowInternalRoutes = true;
121 432 : }
122 :
123 :
124 432 : MSStateHandler::~MSStateHandler() {
125 432 : delete myVCAttrs;
126 432 : }
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 33604 : MSStateHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
189 33604 : MSRouteHandler::myStartElement(element, attrs);
190 33602 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
191 33602 : switch (element) {
192 432 : case SUMO_TAG_SNAPSHOT: {
193 432 : myTime = string2time(attrs.getString(SUMO_ATTR_TIME));
194 432 : const std::string& version = attrs.getString(SUMO_ATTR_VERSION);
195 432 : if (version != VERSION_STRING) {
196 525 : WRITE_WARNINGF(TL("State was written with sumo version % (present: %)!"), version, VERSION_STRING);
197 : }
198 : bool ok;
199 432 : if (attrs.getOpt<bool>(SUMO_ATTR_CONSTRAINTS, nullptr, ok, false)) {
200 7 : MSRailSignalConstraint::clearAll();
201 : }
202 432 : if (attrs.getOpt<bool>(SUMO_ATTR_RAIL, nullptr, ok, false)) {
203 : // init before loading any vehicles to ensure that driveways are built early
204 19 : 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 40 : for (const std::string& laneID : laneIDs) {
243 33 : MSLane* lane = MSLane::dictionary(laneID);
244 33 : 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 81 : case SUMO_TAG_ROUTINGENGINE: {
253 81 : bool ok = true;
254 81 : const SUMOTime lastAdaptation = attrs.get<SUMOTime>(SUMO_ATTR_LAST, nullptr, ok);
255 81 : const int index = attrs.get<int>(SUMO_ATTR_INDEX, nullptr, ok);
256 81 : MSRoutingEngine::initEdgeWeights(SVC_PASSENGER, lastAdaptation, index);
257 162 : if (OptionsCont::getOptions().getBool("device.rerouting.bike-speeds")) {
258 0 : MSRoutingEngine::initEdgeWeights(SVC_BICYCLE);
259 : }
260 81 : 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 903 : case SUMO_TAG_EDGE: {
270 : #ifdef HAVE_FOX
271 903 : MSRoutingEngine::loadState(attrs);
272 : #endif
273 903 : break;
274 : }
275 430 : case SUMO_TAG_DELAY: {
276 430 : if (myVCAttrs != nullptr) {
277 0 : delete myVCAttrs;
278 : }
279 430 : myVCAttrs = attrs.clone();
280 430 : 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 656 : case SUMO_TAG_VTYPE: {
292 656 : myLastParameterised = myCurrentVType;
293 656 : break;
294 : }
295 5550 : case SUMO_TAG_VEHICLE: {
296 5550 : myLastParameterised = myVehicleParameter;
297 5550 : myAttrs = attrs.clone();
298 5550 : break;
299 : }
300 7195 : case SUMO_TAG_DEVICE: {
301 7195 : myDeviceAttrs.push_back(attrs.clone());
302 7195 : 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 652 : case SUMO_TAG_LANE: {
327 : bool ok;
328 652 : const std::string laneID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
329 652 : myCurrentLane = MSLane::dictionary(laneID);
330 652 : if (myCurrentLane == nullptr) {
331 0 : throw ProcessError(TLF("Unknown lane '%' in loaded state.", laneID));
332 : }
333 : break;
334 : }
335 1220 : case SUMO_TAG_VIEWSETTINGS_VEHICLES: {
336 : bool ok;
337 1220 : const std::vector<std::string>& vehIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_VALUE, nullptr, ok, false);
338 : std::vector<SUMOVehicle*> vehs;
339 3253 : for (const std::string& id : vehIDs) {
340 2033 : SUMOVehicle* v = vc.getVehicle(id);
341 : // vehicle could be removed due to options
342 2033 : if (v != nullptr) {
343 2026 : vehs.push_back(v);
344 : myArrived.erase(v);
345 : }
346 : }
347 1220 : 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 634 : myCurrentLane->loadState(vehs);
357 : }
358 : break;
359 1221 : }
360 32 : case SUMO_TAG_LINK: {
361 : bool ok;
362 32 : myCurrentLink = nullptr;
363 32 : const std::string toLaneID = attrs.get<std::string>(SUMO_ATTR_TO, nullptr, ok);
364 67 : for (MSLink* link : myCurrentLane->getLinkCont()) {
365 35 : if (link->getViaLaneOrLane()->getID() == toLaneID) {
366 32 : myCurrentLink = link;
367 : }
368 : }
369 32 : if (myCurrentLink == nullptr) {
370 0 : throw ProcessError("Unknown link from lane '" + myCurrentLane->getID() + "' to lane '" + toLaneID + "' in loaded state");
371 : }
372 : break;
373 : }
374 32 : case SUMO_TAG_APPROACHING: {
375 : bool ok;
376 32 : const std::string vehID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
377 32 : const SUMOTime arrivalTime = attrs.get<SUMOTime>(SUMO_ATTR_ARRIVALTIME, nullptr, ok);
378 32 : const double arrivalSpeed = attrs.get<double>(SUMO_ATTR_ARRIVALSPEED, nullptr, ok);
379 32 : const double leaveSpeed = attrs.get<double>(SUMO_ATTR_DEPARTSPEED, nullptr, ok);
380 32 : const bool setRequest = attrs.get<bool>(SUMO_ATTR_REQUEST, nullptr, ok);
381 32 : const double arrivalSpeedBraking = attrs.get<double>(SUMO_ATTR_ARRIVALSPEEDBRAKING, nullptr, ok);
382 32 : const SUMOTime waitingTime = attrs.get<SUMOTime>(SUMO_ATTR_WAITINGTIME, nullptr, ok);
383 32 : const double dist = attrs.get<double>(SUMO_ATTR_DISTANCE, nullptr, ok);
384 32 : const double latOffset = attrs.getOpt<double>(SUMO_ATTR_POSITION_LAT, nullptr, ok, 0);
385 32 : SUMOVehicle* veh = vc.getVehicle(vehID);
386 32 : myCurrentLink->setApproaching(veh, arrivalTime, arrivalSpeed, leaveSpeed, setRequest, arrivalSpeedBraking, waitingTime, dist, latOffset);
387 32 : if (!MSGlobals::gUseMesoSim) {
388 32 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
389 32 : 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 38 : case SUMO_TAG_DRIVEWAY:
398 : case SUMO_TAG_SUBDRIVEWAY: {
399 38 : MSDriveWay::loadState(attrs, element);
400 38 : break;
401 : }
402 127 : case SUMO_TAG_PARAM: {
403 : bool ok;
404 127 : const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
405 : // circumventing empty string test
406 127 : const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
407 : assert(myLastParameterised != 0);
408 127 : if (myLastParameterised != nullptr) {
409 127 : 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 33595 : MSStateHandler::myEndElement(int element) {
475 33595 : MSRouteHandler::myEndElement(element);
476 33593 : 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 427 : case SUMO_TAG_SNAPSHOT: {
493 427 : if (myVCAttrs == nullptr) {
494 0 : throw ProcessError(TL("Could not load vehicle control state"));
495 : }
496 427 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
497 427 : vc.setState(myVCAttrs->getInt(SUMO_ATTR_NUMBER),
498 427 : myVCAttrs->getInt(SUMO_ATTR_BEGIN),
499 427 : myVCAttrs->getInt(SUMO_ATTR_END),
500 427 : myVCAttrs->getFloat(SUMO_ATTR_DEPART),
501 427 : myVCAttrs->getFloat(SUMO_ATTR_TIME));
502 427 : if (myRemoved > 0) {
503 14 : WRITE_MESSAGEF(TL("Removed % vehicles while loading state."), toString(myRemoved));
504 7 : vc.discountStateRemoved(myRemoved);
505 : }
506 430 : for (SUMOVehicle* v : myArrived) {
507 : // state was created with active option --keep-after-arrival
508 3 : vc.deleteKeptVehicle(v);
509 : }
510 : break;
511 : }
512 : default:
513 : break;
514 : }
515 33593 : if (element != SUMO_TAG_PARAM && myVehicleParameter == nullptr && myCurrentVType == nullptr) {
516 19303 : myLastParameterised = nullptr;
517 : }
518 33593 : }
519 :
520 :
521 : void
522 5550 : MSStateHandler::closeVehicle() {
523 : assert(myVehicleParameter != nullptr);
524 5550 : myVehicleParameter->depart -= myOffset;
525 : // the vehicle was already counted in MSVehicleControl::setState
526 5550 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
527 : // make a copy because myVehicleParameter is reset in closeVehicle()
528 5550 : 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 12737 : for (auto attrs : myDeviceAttrs) {
535 14388 : deviceNames.push_back(MSDevice::getDeviceName(attrs->getString(SUMO_ATTR_ID)));
536 : }
537 5543 : myVehicleParameter->setParameter(MSDevice::LOADSTATE_DEVICENAMES, toString(deviceNames));
538 5543 : MSRouteHandler::closeVehicle();
539 5542 : SUMOVehicle* v = vc.getVehicle(vehID);
540 : // clean up added param after initializing devices in closeVehicle
541 5542 : ((SUMOVehicleParameter&)v->getParameter()).unsetParameter(MSDevice::LOADSTATE_DEVICENAMES);
542 : if (v == nullptr) {
543 : throw ProcessError(TLF("Could not load vehicle '%' from state", vehID));
544 : }
545 5542 : v->setChosenSpeedFactor(myAttrs->getFloat(SUMO_ATTR_SPEEDFACTOR));
546 5542 : v->loadState(*myAttrs, myOffset);
547 :
548 5541 : if (v->hasDeparted()) {
549 : // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
550 2490 : MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(v->getDevice(typeid(MSDevice_Routing)));
551 : if (routingDevice != nullptr) {
552 1937 : routingDevice->notifyEnter(*v, MSMoveReminder::NOTIFICATION_DEPARTED);
553 : }
554 2490 : MSNet::getInstance()->getInsertionControl().alreadyDeparted(v);
555 2490 : if (MSRailSignalControl::hasInstance()) {
556 : // register route for deadlock prevention (vehicleStateChanged would not be called otherwise)
557 62 : MSRailSignalControl::getInstance().vehicleStateChanged(v, MSNet::VehicleState::NEWROUTE, "loadState");
558 : }
559 2490 : vc.handleTriggeredDepart(v, false);
560 2490 : if (v->hasArrived()) {
561 : myArrived.insert(v);
562 : }
563 : }
564 12733 : while (!myDeviceAttrs.empty()) {
565 7192 : const std::string attrID = myDeviceAttrs.back()->getString(SUMO_ATTR_ID);
566 18590 : for (MSVehicleDevice* const dev : v->getDevices()) {
567 11398 : if (dev->getID() == attrID) {
568 7177 : dev->loadState(*myDeviceAttrs.back());
569 : }
570 : }
571 7192 : delete myDeviceAttrs.back();
572 : myDeviceAttrs.pop_back();
573 : }
574 5541 : bool ok = true;
575 5667 : 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 5543 : } 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 5548 : delete myAttrs;
599 5548 : }
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 : /****************************************************************************/
|