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 : /****************************************************************************/
|