Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2012-2024 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/MSDevice_BTreceiver.h>
42 : #include <microsim/devices/MSDevice_ToC.h>
43 : #include <microsim/transportables/MSTransportableControl.h>
44 : #include <microsim/traffic_lights/MSRailSignalControl.h>
45 : #include <microsim/MSEdge.h>
46 : #include <microsim/MSLane.h>
47 : #include <microsim/MSLink.h>
48 : #include <microsim/MSGlobals.h>
49 : #include <microsim/MSNet.h>
50 : #include <microsim/MSVehicleTransfer.h>
51 : #include <microsim/MSInsertionControl.h>
52 : #include <microsim/MSEdgeControl.h>
53 : #include <microsim/MSRoute.h>
54 : #include <microsim/MSVehicleControl.h>
55 : #include <microsim/MSDriverState.h>
56 : #include <netload/NLHandler.h>
57 : #include "MSStateHandler.h"
58 :
59 : #include <mesosim/MESegment.h>
60 : #include <mesosim/MELoop.h>
61 :
62 :
63 : // ===========================================================================
64 : // MSStateTimeHandler method definitions
65 : // ===========================================================================
66 :
67 : SUMOTime
68 406 : MSStateHandler::MSStateTimeHandler::getTime(const std::string& fileName) {
69 : // build handler and parser
70 406 : MSStateTimeHandler handler;
71 406 : handler.setFileName(fileName);
72 406 : handler.myTime = -1;
73 406 : SUMOSAXReader* parser = XMLSubSys::getSAXReader(handler);
74 : try {
75 799 : if (!parser->parseFirst(fileName)) {
76 0 : delete parser;
77 0 : throw ProcessError(TLF("Can not read XML-file '%'.", fileName));
78 : }
79 13 : } catch (ProcessError&) {
80 13 : delete parser;
81 13 : throw;
82 13 : }
83 : // parse
84 57213 : while (parser->parseNext() && handler.myTime != -1);
85 : // clean up
86 388 : if (handler.myTime == -1) {
87 0 : delete parser;
88 0 : throw ProcessError(TLF("Could not parse time from state file '%'", fileName));
89 : }
90 388 : delete parser;
91 388 : return handler.myTime;
92 : }
93 :
94 : void
95 22959 : MSStateHandler::MSStateTimeHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
96 22959 : if (element == SUMO_TAG_SNAPSHOT) {
97 393 : myTime = string2time(attrs.getString(SUMO_ATTR_TIME));
98 : }
99 22959 : }
100 :
101 : // ===========================================================================
102 : // method definitions
103 : // ===========================================================================
104 386 : MSStateHandler::MSStateHandler(const std::string& file, const SUMOTime offset) :
105 : MSRouteHandler(file, true),
106 386 : myOffset(offset),
107 386 : mySegment(nullptr),
108 386 : myCurrentLane(nullptr),
109 386 : myCurrentLink(nullptr),
110 386 : myAttrs(nullptr),
111 386 : myVCAttrs(nullptr),
112 386 : myLastParameterised(nullptr),
113 386 : myRemoved(0),
114 386 : myConstrainedSignal(nullptr) {
115 386 : myAmLoadingState = true;
116 772 : const std::vector<std::string> vehIDs = OptionsCont::getOptions().getStringVector("load-state.remove-vehicles");
117 : myVehiclesToRemove.insert(vehIDs.begin(), vehIDs.end());
118 386 : myAllowInternalRoutes = true;
119 386 : }
120 :
121 :
122 386 : MSStateHandler::~MSStateHandler() {
123 386 : delete myVCAttrs;
124 386 : }
125 :
126 :
127 : void
128 425 : MSStateHandler::saveState(const std::string& file, SUMOTime step, bool usePrefix) {
129 425 : OutputDevice& out = OutputDevice::getDevice(file, usePrefix);
130 425 : out.setPrecision(OptionsCont::getOptions().getInt("save-state.precision"));
131 425 : out.writeHeader<MSEdge>(SUMO_TAG_SNAPSHOT);
132 1275 : out.writeAttr("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance").writeAttr("xsi:noNamespaceSchemaLocation", "http://sumo.dlr.de/xsd/state_file.xsd");
133 : out.writeAttr(SUMO_ATTR_VERSION, VERSION_STRING);
134 425 : out.writeAttr(SUMO_ATTR_TIME, time2string(step));
135 729 : out.writeAttr(SUMO_ATTR_TYPE, MSGlobals::gUseMesoSim ? "meso" : "micro");
136 850 : if (OptionsCont::getOptions().getBool("save-state.constraints")) {
137 14 : out.writeAttr(SUMO_ATTR_CONSTRAINTS, true);
138 : }
139 425 : if (MSDriveWay::haveDriveWays()) {
140 22 : out.writeAttr(SUMO_ATTR_RAIL, true);
141 : }
142 850 : if (OptionsCont::getOptions().getBool("save-state.rng")) {
143 6 : saveRNGs(out);
144 6 : if (!MSGlobals::gUseMesoSim) {
145 3 : MSNet::getInstance()->getEdgeControl().saveState(out);
146 : }
147 : }
148 425 : MSRoute::dict_saveState(out);
149 425 : MSNet::getInstance()->getVehicleControl().saveState(out);
150 425 : MSNet::getInstance()->getInsertionControl().saveState(out);
151 850 : if (OptionsCont::getOptions().getBool("save-state.transportables")) {
152 29 : if (MSNet::getInstance()->hasPersons()) {
153 29 : out.openTag(SUMO_TAG_TRANSPORTABLES).writeAttr(SUMO_ATTR_TYPE, "person");
154 29 : MSNet::getInstance()->getPersonControl().saveState(out);
155 58 : out.closeTag();
156 : }
157 29 : if (MSNet::getInstance()->hasContainers()) {
158 0 : out.openTag(SUMO_TAG_TRANSPORTABLES).writeAttr(SUMO_ATTR_TYPE, "container");
159 0 : MSNet::getInstance()->getContainerControl().saveState(out);
160 0 : out.closeTag();
161 : }
162 : }
163 425 : MSVehicleTransfer::getInstance()->saveState(out);
164 10471 : for (MSEdge* const edge : MSEdge::getAllEdges()) {
165 10046 : if (MSGlobals::gUseMesoSim) {
166 7102 : for (MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*edge); s != nullptr; s = s->getNextSegment()) {
167 5193 : s->saveState(out);
168 : }
169 : } else {
170 16991 : for (MSLane* const lane : edge->getLanes()) {
171 8854 : lane->saveState(out);
172 : }
173 : }
174 : }
175 425 : MSNet::getInstance()->getTLSControl().saveState(out);
176 425 : out.close();
177 425 : }
178 :
179 :
180 : void
181 22932 : MSStateHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
182 22932 : MSRouteHandler::myStartElement(element, attrs);
183 22932 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
184 22932 : switch (element) {
185 386 : case SUMO_TAG_SNAPSHOT: {
186 386 : myTime = string2time(attrs.getString(SUMO_ATTR_TIME));
187 386 : const std::string& version = attrs.getString(SUMO_ATTR_VERSION);
188 386 : if (version != VERSION_STRING) {
189 498 : WRITE_WARNINGF(TL("State was written with sumo version % (present: %)!"), version, VERSION_STRING);
190 : }
191 : bool ok;
192 386 : if (attrs.getOpt<bool>(SUMO_ATTR_CONSTRAINTS, nullptr, ok, false)) {
193 6 : MSRailSignalConstraint::clearAll();
194 : }
195 386 : if (attrs.getOpt<bool>(SUMO_ATTR_RAIL, nullptr, ok, false)) {
196 : // init before loading any vehicles to ensure that driveways are built early
197 13 : MSRailSignalControl::getInstance();
198 : }
199 : break;
200 : }
201 6 : case SUMO_TAG_RNGSTATE: {
202 6 : if (attrs.hasAttribute(SUMO_ATTR_DEFAULT)) {
203 12 : RandHelper::loadState(attrs.getString(SUMO_ATTR_DEFAULT));
204 : }
205 6 : if (attrs.hasAttribute(SUMO_ATTR_RNG_ROUTEHANDLER)) {
206 12 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_ROUTEHANDLER), MSRouteHandler::getParsingRNG());
207 : }
208 6 : if (attrs.hasAttribute(SUMO_ATTR_RNG_INSERTIONCONTROL)) {
209 12 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_INSERTIONCONTROL), MSNet::getInstance()->getInsertionControl().getFlowRNG());
210 : }
211 6 : if (attrs.hasAttribute(SUMO_ATTR_RNG_DEVICE)) {
212 12 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DEVICE), MSDevice::getEquipmentRNG());
213 : }
214 6 : if (attrs.hasAttribute(SUMO_ATTR_RNG_DEVICE_BT)) {
215 12 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DEVICE_BT), MSVehicleDevice_BTreceiver::getEquipmentRNG());
216 : }
217 6 : if (attrs.hasAttribute(SUMO_ATTR_RNG_DRIVERSTATE)) {
218 12 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DRIVERSTATE), OUProcess::getRNG());
219 : }
220 6 : if (attrs.hasAttribute(SUMO_ATTR_RNG_DEVICE_TOC)) {
221 12 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DEVICE_TOC), MSDevice_ToC::getResponseTimeRNG());
222 : }
223 : break;
224 : }
225 384 : case SUMO_TAG_RNGLANE: {
226 384 : const int index = attrs.getInt(SUMO_ATTR_INDEX);
227 384 : const std::string state = attrs.getString(SUMO_ATTR_STATE);
228 384 : MSLane::loadRNGState(index, state);
229 : break;
230 : }
231 : case SUMO_TAG_EDGECONTROL: {
232 : bool ok;
233 : std::list<MSLane*> activeLanes;
234 3 : const std::vector<std::string>& laneIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_LANES, nullptr, ok, false);
235 7 : for (const std::string& laneID : laneIDs) {
236 4 : MSLane* lane = MSLane::dictionary(laneID);
237 4 : if (lane == nullptr) {
238 0 : throw ProcessError(TLF("Unknown lane '%' in loaded state.", laneID));
239 : }
240 : activeLanes.push_back(lane);
241 : }
242 3 : MSNet::getInstance()->getEdgeControl().setActiveLanes(activeLanes);
243 : break;
244 3 : }
245 386 : case SUMO_TAG_DELAY: {
246 386 : if (myVCAttrs != nullptr) {
247 0 : delete myVCAttrs;
248 : }
249 386 : myVCAttrs = attrs.clone();
250 386 : break;
251 : }
252 43 : case SUMO_TAG_FLOWSTATE: {
253 : bool ok;
254 43 : SUMOVehicleParameter* pars = SUMOVehicleParserHelper::parseFlowAttributes(SUMO_TAG_FLOWSTATE, attrs, true, true, -1, -1, true);
255 43 : pars->repetitionsDone = attrs.get<int>(SUMO_ATTR_DONE, pars->id.c_str(), ok);
256 43 : pars->repetitionTotalOffset = attrs.getOptSUMOTimeReporting(SUMO_ATTR_NEXT, pars->id.c_str(), ok, 0);
257 43 : int index = attrs.getInt(SUMO_ATTR_INDEX);
258 43 : MSNet::getInstance()->getInsertionControl().addFlow(pars, index);
259 : break;
260 : }
261 614 : case SUMO_TAG_VTYPE: {
262 614 : myLastParameterised = myCurrentVType;
263 614 : break;
264 : }
265 4424 : case SUMO_TAG_VEHICLE: {
266 4424 : myLastParameterised = myVehicleParameter;
267 4424 : myAttrs = attrs.clone();
268 4424 : break;
269 : }
270 5324 : case SUMO_TAG_DEVICE: {
271 5324 : myDeviceAttrs.push_back(attrs.clone());
272 5324 : break;
273 : }
274 185 : case SUMO_TAG_VEHICLETRANSFER: {
275 185 : MSVehicleTransfer::getInstance()->loadState(attrs, myOffset, vc);
276 185 : break;
277 : }
278 171 : case SUMO_TAG_SEGMENT: {
279 171 : const std::string& segmentID = attrs.getString(SUMO_ATTR_ID);
280 342 : const MSEdge* const edge = MSEdge::dictionary(segmentID.substr(0, segmentID.rfind(":")));
281 171 : int idx = StringUtils::toInt(segmentID.substr(segmentID.rfind(":") + 1));
282 171 : mySegment = MSGlobals::gMesoNet->getSegmentForEdge(*edge);
283 269 : while (idx-- > 0) {
284 98 : mySegment = mySegment->getNextSegment();
285 : }
286 171 : myQueIndex = 0;
287 : break;
288 : }
289 559 : case SUMO_TAG_LANE: {
290 : bool ok;
291 559 : const std::string laneID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
292 559 : myCurrentLane = MSLane::dictionary(laneID);
293 559 : if (myCurrentLane == nullptr) {
294 0 : throw ProcessError(TLF("Unknown lane '%' in loaded state.", laneID));
295 : }
296 : break;
297 : }
298 719 : case SUMO_TAG_VIEWSETTINGS_VEHICLES: {
299 : bool ok;
300 719 : const std::vector<std::string>& vehIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_VALUE, nullptr, ok, false);
301 719 : if (MSGlobals::gUseMesoSim) {
302 362 : mySegment->loadState(vehIDs, MSNet::getInstance()->getVehicleControl(), StringUtils::toLong(attrs.getString(SUMO_ATTR_TIME)) - myOffset, myQueIndex);
303 : } else {
304 538 : myCurrentLane->loadState(vehIDs, MSNet::getInstance()->getVehicleControl());
305 : }
306 719 : myQueIndex++;
307 : break;
308 719 : }
309 37 : case SUMO_TAG_LINK: {
310 : bool ok;
311 37 : myCurrentLink = nullptr;
312 37 : const std::string toLaneID = attrs.get<std::string>(SUMO_ATTR_TO, nullptr, ok);
313 77 : for (MSLink* link : myCurrentLane->getLinkCont()) {
314 40 : if (link->getViaLaneOrLane()->getID() == toLaneID) {
315 37 : myCurrentLink = link;
316 : }
317 : }
318 37 : if (myCurrentLink == nullptr) {
319 0 : throw ProcessError("Unknown link from lane '" + myCurrentLane->getID() + "' to lane '" + toLaneID + "' in loaded state");
320 : }
321 : break;
322 : }
323 37 : case SUMO_TAG_APPROACHING: {
324 : bool ok;
325 37 : const std::string vehID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
326 37 : const SUMOTime arrivalTime = attrs.get<SUMOTime>(SUMO_ATTR_ARRIVALTIME, nullptr, ok);
327 37 : const double arrivalSpeed = attrs.get<double>(SUMO_ATTR_ARRIVALSPEED, nullptr, ok);
328 37 : const double leaveSpeed = attrs.get<double>(SUMO_ATTR_DEPARTSPEED, nullptr, ok);
329 37 : const bool setRequest = attrs.get<bool>(SUMO_ATTR_REQUEST, nullptr, ok);
330 37 : const double arrivalSpeedBraking = attrs.get<double>(SUMO_ATTR_ARRIVALSPEEDBRAKING, nullptr, ok);
331 37 : const SUMOTime waitingTime = attrs.get<SUMOTime>(SUMO_ATTR_WAITINGTIME, nullptr, ok);
332 37 : const double dist = attrs.get<double>(SUMO_ATTR_DISTANCE, nullptr, ok);
333 37 : const double latOffset = attrs.getOpt<double>(SUMO_ATTR_POSITION_LAT, nullptr, ok, 0);
334 37 : SUMOVehicle* veh = vc.getVehicle(vehID);
335 37 : myCurrentLink->setApproaching(veh, arrivalTime, arrivalSpeed, leaveSpeed, setRequest, arrivalSpeedBraking, waitingTime, dist, latOffset);
336 37 : if (!MSGlobals::gUseMesoSim) {
337 37 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(veh);
338 37 : microVeh->loadPreviousApproaching(myCurrentLink, setRequest, arrivalTime, arrivalSpeed, arrivalSpeedBraking, dist, leaveSpeed);
339 : }
340 : break;
341 : }
342 4 : case SUMO_TAG_RAILSIGNAL_CONSTRAINT_TRACKER: {
343 4 : MSRailSignalConstraint_Predecessor::loadState(attrs);
344 4 : break;
345 : }
346 29 : case SUMO_TAG_DRIVEWAY:
347 : case SUMO_TAG_SUBDRIVEWAY: {
348 29 : MSDriveWay::loadState(attrs, element);
349 29 : break;
350 : }
351 129 : case SUMO_TAG_PARAM: {
352 : bool ok;
353 129 : const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
354 : // circumventing empty string test
355 129 : const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
356 : assert(myLastParameterised != 0);
357 129 : if (myLastParameterised != nullptr) {
358 129 : myLastParameterised->setParameter(key, val);
359 : }
360 : break;
361 : }
362 34 : case SUMO_TAG_TRANSPORTABLES:
363 34 : if (attrs.getString(SUMO_ATTR_TYPE) == "person") {
364 68 : MSNet::getInstance()->getPersonControl().loadState(attrs.getString(SUMO_ATTR_STATE));
365 : }
366 34 : if (attrs.getString(SUMO_ATTR_TYPE) == "container") {
367 0 : MSNet::getInstance()->getContainerControl().loadState(attrs.getString(SUMO_ATTR_STATE));
368 : }
369 : break;
370 48 : case SUMO_TAG_PERSON:
371 : case SUMO_TAG_CONTAINER:
372 48 : myAttrs = attrs.clone();
373 48 : break;
374 16 : case SUMO_TAG_RAILSIGNAL_CONSTRAINTS: {
375 16 : bool ok = true;
376 16 : const std::string signalID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
377 16 : if (!MSNet::getInstance()->getTLSControl().knows(signalID)) {
378 0 : throw InvalidArgument("Rail signal '" + signalID + "' in railSignalConstraints loaded from state is not known");
379 : }
380 16 : myConstrainedSignal = dynamic_cast<MSRailSignal*>(MSNet::getInstance()->getTLSControl().get(signalID).getDefault());
381 16 : if (myConstrainedSignal == nullptr) {
382 0 : throw InvalidArgument("Traffic light '" + signalID + "' is not a rail signal");
383 : }
384 : break;
385 : }
386 20 : case SUMO_TAG_PREDECESSOR: // intended fall-through
387 : case SUMO_TAG_INSERTION_PREDECESSOR: // intended fall-through
388 : case SUMO_TAG_FOE_INSERTION: // intended fall-through
389 : case SUMO_TAG_INSERTION_ORDER: // intended fall-through
390 : case SUMO_TAG_BIDI_PREDECESSOR:
391 20 : myLastParameterised = NLHandler::addPredecessorConstraint(element, attrs, myConstrainedSignal);
392 20 : break;
393 1435 : case SUMO_TAG_TLLOGIC: {
394 : bool ok;
395 1435 : const std::string tlID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
396 1435 : const std::string programID = attrs.get<std::string>(SUMO_ATTR_PROGRAMID, tlID.c_str(), ok);
397 1435 : const int phase = attrs.get<int>(SUMO_ATTR_PHASE, tlID.c_str(), ok);
398 1435 : const SUMOTime spentDuration = attrs.get<SUMOTime>(SUMO_ATTR_DURATION, tlID.c_str(), ok);
399 1435 : MSTLLogicControl& tlc = MSNet::getInstance()->getTLSControl();
400 1435 : MSTrafficLightLogic* tl = tlc.get(tlID, programID);
401 1435 : if (tl == nullptr) {
402 8 : if (programID == "online") {
403 24 : WRITE_WARNINGF(TL("Ignoring program '%' for traffic light '%' in loaded state"), programID, tlID);
404 : return;
405 : } else {
406 0 : throw ProcessError("Unknown program '" + programID + "' for traffic light '" + tlID + "'");
407 : }
408 : }
409 1427 : if (phase >= tl->getPhaseNumber()) {
410 0 : throw ProcessError("Invalid phase '" + toString(phase) + "' for traffic light '" + tlID + "'");
411 : }
412 : // might not be set if the phase happens to match and there are multiple programs
413 1427 : tl->loadState(tlc, myTime, phase, spentDuration);
414 : break;
415 : }
416 : default:
417 : break;
418 : }
419 : }
420 :
421 :
422 : void
423 22932 : MSStateHandler::myEndElement(int element) {
424 22932 : MSRouteHandler::myEndElement(element);
425 22932 : switch (element) {
426 48 : case SUMO_TAG_PERSON:
427 : case SUMO_TAG_CONTAINER: {
428 48 : MSTransportableControl& tc = (element == SUMO_TAG_PERSON ? MSNet::getInstance()->getPersonControl() : MSNet::getInstance()->getContainerControl());
429 48 : MSTransportable* transportable = tc.get(myAttrs->getString(SUMO_ATTR_ID));
430 48 : transportable->loadState(myAttrs->getString(SUMO_ATTR_STATE));
431 48 : tc.fixLoadCount(transportable);
432 48 : delete myAttrs;
433 48 : myAttrs = nullptr;
434 48 : break;
435 : }
436 386 : case SUMO_TAG_SNAPSHOT: {
437 386 : if (myVCAttrs == nullptr) {
438 0 : throw ProcessError(TL("Could not load vehicle control state"));
439 : }
440 386 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
441 386 : vc.setState(myVCAttrs->getInt(SUMO_ATTR_NUMBER),
442 386 : myVCAttrs->getInt(SUMO_ATTR_BEGIN),
443 386 : myVCAttrs->getInt(SUMO_ATTR_END),
444 386 : myVCAttrs->getFloat(SUMO_ATTR_DEPART),
445 386 : myVCAttrs->getFloat(SUMO_ATTR_TIME));
446 386 : if (myRemoved > 0) {
447 12 : WRITE_MESSAGEF(TL("Removed % vehicles while loading state."), toString(myRemoved));
448 6 : vc.discountStateRemoved(myRemoved);
449 : }
450 : break;
451 : }
452 : default:
453 : break;
454 : }
455 22932 : if (element != SUMO_TAG_PARAM && myVehicleParameter == nullptr && myCurrentVType == nullptr) {
456 14025 : myLastParameterised = nullptr;
457 : }
458 22932 : }
459 :
460 :
461 : void
462 4424 : MSStateHandler::closeVehicle() {
463 : assert(myVehicleParameter != nullptr);
464 4424 : myVehicleParameter->depart -= myOffset;
465 : // the vehicle was already counted in MSVehicleControl::setState
466 4424 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
467 : // make a copy because myVehicleParameter is reset in closeVehicle()
468 4424 : const std::string vehID = myVehicleParameter->id;
469 : if (myVehiclesToRemove.count(vehID) == 0) {
470 4418 : MSRouteHandler::closeVehicle();
471 4418 : SUMOVehicle* v = vc.getVehicle(vehID);
472 4418 : if (v == nullptr) {
473 0 : throw ProcessError(TLF("Could not load vehicle '%' from state", vehID));
474 : }
475 4418 : v->setChosenSpeedFactor(myAttrs->getFloat(SUMO_ATTR_SPEEDFACTOR));
476 4418 : v->loadState(*myAttrs, myOffset);
477 :
478 4418 : if (v->hasDeparted()) {
479 : // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
480 1798 : MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(v->getDevice(typeid(MSDevice_Routing)));
481 : if (routingDevice != nullptr) {
482 1355 : routingDevice->notifyEnter(*v, MSMoveReminder::NOTIFICATION_DEPARTED);
483 : }
484 1798 : MSNet::getInstance()->getInsertionControl().alreadyDeparted(v);
485 1798 : if (MSRailSignalControl::hasInstance()) {
486 : // register route for deadlock prevention (vehicleStateChanged would not be called otherwise)
487 42 : MSRailSignalControl::getInstance().vehicleStateChanged(v, MSNet::VehicleState::NEWROUTE, "loadState");
488 : }
489 1798 : vc.handleTriggeredDepart(v, false);
490 1798 : if (v->hasArrived()) {
491 : // state was created with active option --keep-after-arrival
492 4 : vc.deleteKeptVehicle(v);
493 : }
494 : }
495 9742 : while (!myDeviceAttrs.empty()) {
496 5324 : const std::string attrID = myDeviceAttrs.back()->getString(SUMO_ATTR_ID);
497 12574 : for (MSVehicleDevice* const dev : v->getDevices()) {
498 7250 : if (dev->getID() == attrID) {
499 4936 : dev->loadState(*myDeviceAttrs.back());
500 : }
501 : }
502 5324 : delete myDeviceAttrs.back();
503 : myDeviceAttrs.pop_back();
504 : }
505 : } else {
506 6 : delete myVehicleParameter;
507 6 : myVehicleParameter = nullptr;
508 6 : myRemoved++;
509 : }
510 4424 : delete myAttrs;
511 4424 : }
512 :
513 :
514 : void
515 6 : MSStateHandler::saveRNGs(OutputDevice& out) {
516 6 : out.openTag(SUMO_TAG_RNGSTATE);
517 6 : out.writeAttr(SUMO_ATTR_DEFAULT, RandHelper::saveState());
518 6 : out.writeAttr(SUMO_ATTR_RNG_ROUTEHANDLER, RandHelper::saveState(MSRouteHandler::getParsingRNG()));
519 6 : out.writeAttr(SUMO_ATTR_RNG_INSERTIONCONTROL, RandHelper::saveState(MSNet::getInstance()->getInsertionControl().getFlowRNG()));
520 6 : out.writeAttr(SUMO_ATTR_RNG_DEVICE, RandHelper::saveState(MSDevice::getEquipmentRNG()));
521 6 : out.writeAttr(SUMO_ATTR_RNG_DEVICE_BT, RandHelper::saveState(MSDevice_BTreceiver::getRNG()));
522 6 : out.writeAttr(SUMO_ATTR_RNG_DRIVERSTATE, RandHelper::saveState(OUProcess::getRNG()));
523 6 : out.writeAttr(SUMO_ATTR_RNG_DEVICE_TOC, RandHelper::saveState(MSDevice_ToC::getResponseTimeRNG()));
524 6 : MSLane::saveRNGStates(out);
525 6 : out.closeTag();
526 :
527 6 : }
528 :
529 :
530 : /****************************************************************************/
|