Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2012-2026 German Aerospace Center (DLR) and others.
4 : // This program and the accompanying materials are made available under the
5 : // terms of the Eclipse Public License 2.0 which is available at
6 : // https://www.eclipse.org/legal/epl-2.0/
7 : // This Source Code may also be made available under the following Secondary
8 : // Licenses when the conditions for such availability set forth in the Eclipse
9 : // Public License 2.0 are satisfied: GNU General Public License, version 2
10 : // or later which is available at
11 : // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 : // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 : /****************************************************************************/
14 : /// @file MSStateHandler.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Michael Behrisch
17 : /// @author Jakob Erdmann
18 : /// @date Thu, 13 Dec 2012
19 : ///
20 : // Parser and output filter for routes and vehicles state saving and loading
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #ifdef HAVE_VERSION_H
25 : #include <version.h>
26 : #endif
27 :
28 : #include <sstream>
29 : #include <utils/common/StringUtils.h>
30 : #include <utils/options/OptionsCont.h>
31 : #include <utils/iodevices/OutputDevice.h>
32 : #include <utils/xml/SUMOXMLDefinitions.h>
33 : #include <utils/xml/SUMOSAXReader.h>
34 : #include <utils/xml/XMLSubSys.h>
35 : #include <utils/vehicle/SUMOVehicleParserHelper.h>
36 : #include <microsim/traffic_lights/MSTLLogicControl.h>
37 : #include <microsim/traffic_lights/MSRailSignalConstraint.h>
38 : #include <microsim/traffic_lights/MSRailSignal.h>
39 : #include <microsim/traffic_lights/MSDriveWay.h>
40 : #include <microsim/devices/MSDevice_Routing.h>
41 : #include <microsim/devices/MSRoutingEngine.h>
42 : #include <microsim/devices/MSDevice_BTreceiver.h>
43 : #include <microsim/devices/MSDevice_ToC.h>
44 : #include <microsim/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 454 : MSStateHandler::MSStateTimeHandler::getTime(const std::string& fileName) {
70 : // build handler and parser
71 454 : MSStateTimeHandler handler;
72 454 : handler.setFileName(fileName);
73 454 : handler.myTime = -1;
74 454 : SUMOSAXReader* parser = XMLSubSys::getSAXReader(handler);
75 : try {
76 897 : 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 82705 : while (parser->parseNext() && handler.myTime != -1);
86 : // clean up
87 438 : if (handler.myTime == -1) {
88 0 : delete parser;
89 0 : throw ProcessError(TLF("Could not parse time from state file '%'", fileName));
90 : }
91 438 : delete parser;
92 438 : return handler.myTime;
93 : }
94 :
95 : void
96 33981 : MSStateHandler::MSStateTimeHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
97 33981 : if (element == SUMO_TAG_SNAPSHOT) {
98 443 : myTime = string2time(attrs.getString(SUMO_ATTR_TIME));
99 : }
100 33981 : }
101 :
102 : // ===========================================================================
103 : // method definitions
104 : // ===========================================================================
105 436 : MSStateHandler::MSStateHandler(const std::string& file, const SUMOTime offset) :
106 : MSRouteHandler(file, true),
107 436 : myOffset(offset),
108 436 : mySegment(nullptr),
109 436 : myCurrentLane(nullptr),
110 436 : myCurrentLink(nullptr),
111 436 : myAttrs(nullptr),
112 436 : myVCAttrs(nullptr),
113 436 : myLastParameterised(nullptr),
114 436 : myRemoved(0),
115 436 : myFlowIndex(-1),
116 436 : myConstrainedSignal(nullptr) {
117 436 : myAmLoadingState = true;
118 872 : const std::vector<std::string> vehIDs = OptionsCont::getOptions().getStringVector("load-state.remove-vehicles");
119 : myVehiclesToRemove.insert(vehIDs.begin(), vehIDs.end());
120 436 : myAllowInternalRoutes = true;
121 436 : }
122 :
123 :
124 436 : MSStateHandler::~MSStateHandler() {
125 436 : delete myVCAttrs;
126 436 : }
127 :
128 :
129 : void
130 479 : MSStateHandler::saveState(const std::string& file, SUMOTime step, bool usePrefix) {
131 479 : OutputDevice& out = OutputDevice::getDevice(file, usePrefix);
132 479 : const int statePrecision = OptionsCont::getOptions().getInt("save-state.precision");
133 479 : out.setPrecision(statePrecision);
134 479 : const int defaultPrecision = gPrecision;
135 479 : gPrecision = statePrecision;
136 : std::map<SumoXMLAttr, std::string> attrs;
137 479 : attrs[SUMO_ATTR_VERSION] = VERSION_STRING;
138 479 : attrs[SUMO_ATTR_TIME] = time2string(step);
139 808 : attrs[SUMO_ATTR_TYPE] = MSGlobals::gUseMesoSim ? "meso" : "micro";
140 958 : if (OptionsCont::getOptions().getBool("save-state.constraints")) {
141 18 : attrs[SUMO_ATTR_CONSTRAINTS] = "1";
142 : }
143 479 : if (MSDriveWay::haveDriveWays()) {
144 42 : attrs[SUMO_ATTR_RAIL] = "1";
145 : }
146 958 : out.writeXMLHeader("snapshot", "state_file.xsd", attrs);
147 958 : if (OptionsCont::getOptions().getBool("save-state.rng")) {
148 13 : saveRNGs(out);
149 13 : if (!MSGlobals::gUseMesoSim) {
150 8 : MSNet::getInstance()->getEdgeControl().saveState(out);
151 : }
152 : }
153 479 : MSRoute::dict_saveState(out);
154 479 : MSNet::getInstance()->getVehicleControl().saveState(out);
155 479 : MSNet::getInstance()->getInsertionControl().saveState(out);
156 958 : 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 479 : MSVehicleTransfer::getInstance()->saveState(out);
169 12737 : for (MSEdge* const edge : MSEdge::getAllEdges()) {
170 12258 : if (MSGlobals::gUseMesoSim) {
171 14402 : for (MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*edge); s != nullptr; s = s->getNextSegment()) {
172 7724 : s->saveState(out);
173 : }
174 : } else {
175 18647 : for (MSLane* const lane : edge->getLanes()) {
176 9728 : lane->saveState(out);
177 : }
178 : }
179 : }
180 479 : MSNet::getInstance()->getTLSControl().saveState(out);
181 479 : MSRoutingEngine::saveState(out);
182 479 : out.close();
183 479 : gPrecision = defaultPrecision;
184 479 : }
185 :
186 :
187 : void
188 33908 : MSStateHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
189 33908 : MSRouteHandler::myStartElement(element, attrs);
190 33906 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
191 33906 : switch (element) {
192 436 : case SUMO_TAG_SNAPSHOT: {
193 436 : myTime = string2time(attrs.getString(SUMO_ATTR_TIME));
194 436 : const std::string& version = attrs.getString(SUMO_ATTR_VERSION);
195 436 : if (version != VERSION_STRING) {
196 528 : WRITE_WARNINGF(TL("State was written with sumo version % (present: %)!"), version, VERSION_STRING);
197 : }
198 : bool ok;
199 436 : if (attrs.getOpt<bool>(SUMO_ATTR_CONSTRAINTS, nullptr, ok, false)) {
200 7 : MSRailSignalConstraint::clearAll();
201 : }
202 436 : 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 13 : case SUMO_TAG_RNGSTATE: {
209 13 : if (attrs.hasAttribute(SUMO_ATTR_DEFAULT)) {
210 26 : RandHelper::loadState(attrs.getString(SUMO_ATTR_DEFAULT));
211 : }
212 13 : if (attrs.hasAttribute(SUMO_ATTR_RNG_ROUTEHANDLER)) {
213 26 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_ROUTEHANDLER), MSRouteHandler::getParsingRNG());
214 : }
215 13 : if (attrs.hasAttribute(SUMO_ATTR_RNG_INSERTIONCONTROL)) {
216 26 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_INSERTIONCONTROL), MSNet::getInstance()->getInsertionControl().getFlowRNG());
217 : }
218 13 : if (attrs.hasAttribute(SUMO_ATTR_RNG_DEVICE)) {
219 26 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DEVICE), MSDevice::getEquipmentRNG());
220 : }
221 13 : if (attrs.hasAttribute(SUMO_ATTR_RNG_DEVICE_BT)) {
222 26 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DEVICE_BT), MSVehicleDevice_BTreceiver::getEquipmentRNG());
223 : }
224 13 : if (attrs.hasAttribute(SUMO_ATTR_RNG_DRIVERSTATE)) {
225 26 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DRIVERSTATE), OUProcess::getRNG());
226 : }
227 13 : if (attrs.hasAttribute(SUMO_ATTR_RNG_DEVICE_TOC)) {
228 26 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DEVICE_TOC), MSDevice_ToC::getResponseTimeRNG());
229 : }
230 : break;
231 : }
232 832 : case SUMO_TAG_RNGLANE: {
233 832 : const int index = attrs.getInt(SUMO_ATTR_INDEX);
234 832 : const std::string state = attrs.getString(SUMO_ATTR_STATE);
235 832 : MSLane::loadRNGState(index, state);
236 : break;
237 : }
238 : case SUMO_TAG_EDGECONTROL: {
239 : bool ok;
240 : std::list<MSLane*> activeLanes;
241 8 : const std::vector<std::string>& laneIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_LANES, nullptr, ok, false);
242 41 : 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 8 : MSNet::getInstance()->getEdgeControl().setActiveLanes(activeLanes);
250 : break;
251 8 : }
252 191 : case SUMO_TAG_ROUTINGENGINE: {
253 191 : bool ok = true;
254 191 : const SUMOTime lastAdaptation = attrs.get<SUMOTime>(SUMO_ATTR_LAST, nullptr, ok);
255 191 : const int index = attrs.get<int>(SUMO_ATTR_INDEX, nullptr, ok);
256 191 : MSRoutingEngine::initEdgeWeights(SVC_PASSENGER, lastAdaptation, index);
257 382 : if (OptionsCont::getOptions().getBool("device.rerouting.bike-speeds")) {
258 0 : MSRoutingEngine::initEdgeWeights(SVC_BICYCLE);
259 : }
260 191 : 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 1433 : case SUMO_TAG_EDGE: {
270 : #ifdef HAVE_FOX
271 1433 : MSRoutingEngine::loadState(attrs);
272 : #endif
273 1433 : break;
274 : }
275 434 : case SUMO_TAG_DELAY: {
276 434 : if (myVCAttrs != nullptr) {
277 0 : delete myVCAttrs;
278 : }
279 434 : myVCAttrs = attrs.clone();
280 434 : break;
281 : }
282 56 : case SUMO_TAG_FLOWSTATE: {
283 : bool ok;
284 56 : SUMOVehicleParameter* pars = SUMOVehicleParserHelper::parseFlowAttributes(SUMO_TAG_FLOWSTATE, attrs, true, true, -1, -1, true);
285 56 : pars->repetitionsDone = attrs.get<int>(SUMO_ATTR_DONE, pars->id.c_str(), ok);
286 56 : pars->repetitionTotalOffset = attrs.getOptSUMOTimeReporting(SUMO_ATTR_NEXT, pars->id.c_str(), ok, 0);
287 56 : myFlowIndex = attrs.getInt(SUMO_ATTR_INDEX);
288 56 : myVehicleParameter = pars;
289 : break;
290 : }
291 664 : case SUMO_TAG_VTYPE: {
292 664 : myLastParameterised = myCurrentVType;
293 664 : break;
294 : }
295 5376 : case SUMO_TAG_VEHICLE: {
296 5376 : myLastParameterised = myVehicleParameter;
297 5376 : myAttrs = attrs.clone();
298 5376 : break;
299 : }
300 7024 : case SUMO_TAG_DEVICE: {
301 7024 : myDeviceAttrs.push_back(attrs.clone());
302 7024 : break;
303 : }
304 128 : case SUMO_TAG_REMINDER: {
305 128 : myReminderAttrs.push_back(attrs.clone());
306 128 : break;
307 : }
308 186 : case SUMO_TAG_VEHICLETRANSFER: {
309 186 : MSVehicleTransfer::getInstance()->loadState(attrs, myOffset, vc);
310 186 : break;
311 : }
312 576 : case SUMO_TAG_SEGMENT: {
313 576 : const std::string& segmentID = attrs.getString(SUMO_ATTR_ID);
314 1152 : const MSEdge* const edge = MSEdge::dictionary(segmentID.substr(0, segmentID.rfind(":")));
315 576 : int idx = StringUtils::toInt(segmentID.substr(segmentID.rfind(":") + 1));
316 576 : mySegment = MSGlobals::gMesoNet->getSegmentForEdge(*edge);
317 866 : while (idx-- > 0 && mySegment != nullptr) {
318 290 : mySegment = mySegment->getNextSegment();
319 : }
320 576 : if (mySegment == nullptr) {
321 0 : throw ProcessError(TLF("Unknown segment '%' in loaded state.", segmentID));
322 : }
323 576 : myQueIndex = 0;
324 : break;
325 : }
326 655 : case SUMO_TAG_LANE: {
327 : bool ok;
328 655 : const std::string laneID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
329 655 : myCurrentLane = MSLane::dictionary(laneID);
330 655 : if (myCurrentLane == nullptr) {
331 0 : throw ProcessError(TLF("Unknown lane '%' in loaded state.", laneID));
332 : }
333 : break;
334 : }
335 1223 : case SUMO_TAG_VIEWSETTINGS_VEHICLES: {
336 : bool ok;
337 1223 : const std::vector<std::string>& vehIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_VALUE, nullptr, ok, false);
338 : std::vector<SUMOVehicle*> vehs;
339 3213 : for (const std::string& id : vehIDs) {
340 1990 : SUMOVehicle* v = vc.getVehicle(id);
341 : // vehicle could be removed due to options
342 1990 : if (v != nullptr) {
343 1983 : vehs.push_back(v);
344 : myArrived.erase(v);
345 : }
346 : }
347 1223 : if (MSGlobals::gUseMesoSim) {
348 589 : 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 588 : const SUMOTime blockTime = StringUtils::toLong(attrs.getString(SUMO_ATTR_TIME));
352 588 : const SUMOTime entryBlockTime = StringUtils::toLong(attrs.getString(SUMO_ATTR_BLOCKTIME));
353 588 : mySegment->loadState(vehs, blockTime - myOffset, entryBlockTime - myOffset, myQueIndex);
354 588 : myQueIndex++;
355 : } else {
356 634 : myCurrentLane->loadState(vehs);
357 : }
358 : break;
359 1224 : }
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 129 : case SUMO_TAG_PARAM: {
403 : bool ok;
404 129 : const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
405 : // circumventing empty string test
406 129 : const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
407 : assert(myLastParameterised != 0);
408 129 : if (myLastParameterised != nullptr) {
409 129 : 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 1704 : case SUMO_TAG_TLLOGIC: {
445 : bool ok;
446 1704 : const std::string tlID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
447 1704 : const std::string programID = attrs.get<std::string>(SUMO_ATTR_PROGRAMID, tlID.c_str(), ok);
448 1704 : const int phase = attrs.get<int>(SUMO_ATTR_PHASE, tlID.c_str(), ok);
449 1704 : const SUMOTime spentDuration = attrs.get<SUMOTime>(SUMO_ATTR_DURATION, tlID.c_str(), ok);
450 1704 : const bool active = attrs.get<bool>(SUMO_ATTR_ACTIVE, tlID.c_str(), ok);
451 1704 : MSTLLogicControl& tlc = MSNet::getInstance()->getTLSControl();
452 1704 : MSTrafficLightLogic* tl = tlc.get(tlID, programID);
453 1704 : if (tl == nullptr) {
454 8 : if (programID == "online") {
455 24 : WRITE_WARNINGF(TL("Ignoring program '%' for traffic light '%' in loaded state"), programID, tlID);
456 : return;
457 : } else {
458 0 : throw ProcessError("Unknown program '" + programID + "' for traffic light '" + tlID + "'");
459 : }
460 : }
461 1696 : if (phase >= tl->getPhaseNumber()) {
462 0 : throw ProcessError("Invalid phase '" + toString(phase) + "' for traffic light '" + tlID + "'");
463 : }
464 : // might not be set if the phase happens to match and there are multiple programs
465 1696 : tl->loadState(tlc, myTime, phase, spentDuration, active);
466 : break;
467 : }
468 : default:
469 : break;
470 : }
471 : }
472 :
473 :
474 : void
475 33899 : MSStateHandler::myEndElement(int element) {
476 33899 : MSRouteHandler::myEndElement(element);
477 33897 : switch (element) {
478 48 : case SUMO_TAG_PERSON:
479 : case SUMO_TAG_CONTAINER: {
480 48 : MSTransportableControl& tc = (element == SUMO_TAG_PERSON ? MSNet::getInstance()->getPersonControl() : MSNet::getInstance()->getContainerControl());
481 48 : MSTransportable* transportable = tc.get(myAttrs->getString(SUMO_ATTR_ID));
482 48 : transportable->loadState(myAttrs->getString(SUMO_ATTR_STATE));
483 48 : tc.fixLoadCount(transportable);
484 48 : delete myAttrs;
485 48 : myAttrs = nullptr;
486 48 : break;
487 : }
488 56 : case SUMO_TAG_FLOWSTATE: {
489 56 : MSNet::getInstance()->getInsertionControl().addFlow(myVehicleParameter, myFlowIndex);
490 56 : myVehicleParameter = nullptr;
491 56 : break;
492 : }
493 431 : case SUMO_TAG_SNAPSHOT: {
494 431 : if (myVCAttrs == nullptr) {
495 0 : throw ProcessError(TL("Could not load vehicle control state"));
496 : }
497 431 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
498 431 : vc.setState(myVCAttrs->getInt(SUMO_ATTR_NUMBER),
499 431 : myVCAttrs->getInt(SUMO_ATTR_BEGIN),
500 431 : myVCAttrs->getInt(SUMO_ATTR_END),
501 431 : myVCAttrs->getFloat(SUMO_ATTR_DEPART),
502 431 : myVCAttrs->getFloat(SUMO_ATTR_TIME));
503 431 : if (myRemoved > 0) {
504 14 : WRITE_MESSAGEF(TL("Removed % vehicles while loading state."), toString(myRemoved));
505 7 : vc.discountStateRemoved(myRemoved);
506 : }
507 434 : for (SUMOVehicle* v : myArrived) {
508 : // state was created with active option --keep-after-arrival
509 3 : vc.deleteKeptVehicle(v);
510 : }
511 : break;
512 : }
513 : default:
514 : break;
515 : }
516 33897 : if (element != SUMO_TAG_PARAM && myVehicleParameter == nullptr && myCurrentVType == nullptr) {
517 19767 : myLastParameterised = nullptr;
518 : }
519 33897 : }
520 :
521 :
522 : void
523 5376 : MSStateHandler::closeVehicle() {
524 : assert(myVehicleParameter != nullptr);
525 5376 : myVehicleParameter->depart -= myOffset;
526 : // the vehicle was already counted in MSVehicleControl::setState
527 5376 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
528 : // make a copy because myVehicleParameter is reset in closeVehicle()
529 5376 : const std::string vehID = myVehicleParameter->id;
530 : if (myVehiclesToRemove.count(vehID) == 0) {
531 :
532 : // devices that influence simulation behavior must replicate stochastic assignment
533 : // also, setting the parameter avoids extra calls to MSDevice::myEquipmentRNG (which would pollute replication)
534 : std::vector<std::string> deviceNames;
535 12392 : for (auto attrs : myDeviceAttrs) {
536 14046 : deviceNames.push_back(MSDevice::getDeviceName(attrs->getString(SUMO_ATTR_ID)));
537 : }
538 5369 : myVehicleParameter->setParameter(MSDevice::LOADSTATE_DEVICENAMES, toString(deviceNames));
539 5369 : MSRouteHandler::closeVehicle();
540 5368 : SUMOVehicle* v = vc.getVehicle(vehID);
541 : // clean up added param after initializing devices in closeVehicle
542 5368 : ((SUMOVehicleParameter&)v->getParameter()).unsetParameter(MSDevice::LOADSTATE_DEVICENAMES);
543 : if (v == nullptr) {
544 : throw ProcessError(TLF("Could not load vehicle '%' from state", vehID));
545 : }
546 5368 : v->setChosenSpeedFactor(myAttrs->getFloat(SUMO_ATTR_SPEEDFACTOR));
547 5368 : v->loadState(*myAttrs, myOffset);
548 :
549 5367 : if (v->hasDeparted()) {
550 : // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
551 2433 : MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(v->getDevice(typeid(MSDevice_Routing)));
552 : if (routingDevice != nullptr) {
553 1878 : routingDevice->notifyEnter(*v, MSMoveReminder::NOTIFICATION_DEPARTED);
554 : }
555 2433 : MSNet::getInstance()->getInsertionControl().alreadyDeparted(v);
556 2433 : if (MSRailSignalControl::hasInstance()) {
557 : // register route for deadlock prevention (vehicleStateChanged would not be called otherwise)
558 66 : MSRailSignalControl::getInstance().vehicleStateChanged(v, MSNet::VehicleState::NEWROUTE, "loadState");
559 : }
560 2433 : vc.handleTriggeredDepart(v, false);
561 2433 : if (v->hasArrived()) {
562 : myArrived.insert(v);
563 : }
564 : }
565 12388 : while (!myDeviceAttrs.empty()) {
566 7021 : const std::string attrID = myDeviceAttrs.back()->getString(SUMO_ATTR_ID);
567 18256 : for (MSVehicleDevice* const dev : v->getDevices()) {
568 11235 : if (dev->getID() == attrID) {
569 7006 : dev->loadState(*myDeviceAttrs.back());
570 : }
571 : }
572 7021 : delete myDeviceAttrs.back();
573 : myDeviceAttrs.pop_back();
574 : }
575 5367 : bool ok = true;
576 5493 : while (!myReminderAttrs.empty()) {
577 126 : const std::string attrID = myReminderAttrs.back()->getString(SUMO_ATTR_ID);
578 126 : const SUMOTime time = myReminderAttrs.back()->get<SUMOTime>(SUMO_ATTR_TIME, nullptr, ok, false);
579 126 : const double pos = myReminderAttrs.back()->get<double>(SUMO_ATTR_POSITION, nullptr, ok, false);
580 126 : const auto& remDict = MSNet::getInstance()->getDetectorControl().getAllReminders();
581 : auto it = remDict.find(attrID);
582 126 : if (it != remDict.end()) {
583 6 : it->second->loadReminderState(v->getNumericalID(), time, pos);
584 : }
585 126 : delete myReminderAttrs.back();
586 : myReminderAttrs.pop_back();
587 : }
588 5369 : } else {
589 7 : const std::string embeddedRouteID = "!" + myVehicleParameter->id;
590 7 : if (MSRoute::hasRoute(embeddedRouteID)) {
591 1 : ConstMSRoutePtr embedded = MSRoute::dictionary(embeddedRouteID);
592 1 : embedded->checkRemoval();
593 : }
594 7 : delete myVehicleParameter;
595 :
596 7 : myVehicleParameter = nullptr;
597 7 : myRemoved++;
598 : }
599 5374 : delete myAttrs;
600 5374 : }
601 :
602 :
603 : void
604 13 : MSStateHandler::saveRNGs(OutputDevice& out) {
605 13 : out.openTag(SUMO_TAG_RNGSTATE);
606 13 : out.writeAttr(SUMO_ATTR_DEFAULT, RandHelper::saveState());
607 13 : out.writeAttr(SUMO_ATTR_RNG_ROUTEHANDLER, RandHelper::saveState(MSRouteHandler::getParsingRNG()));
608 13 : out.writeAttr(SUMO_ATTR_RNG_INSERTIONCONTROL, RandHelper::saveState(MSNet::getInstance()->getInsertionControl().getFlowRNG()));
609 13 : out.writeAttr(SUMO_ATTR_RNG_DEVICE, RandHelper::saveState(MSDevice::getEquipmentRNG()));
610 13 : out.writeAttr(SUMO_ATTR_RNG_DEVICE_BT, RandHelper::saveState(MSDevice_BTreceiver::getRNG()));
611 13 : out.writeAttr(SUMO_ATTR_RNG_DRIVERSTATE, RandHelper::saveState(OUProcess::getRNG()));
612 13 : out.writeAttr(SUMO_ATTR_RNG_DEVICE_TOC, RandHelper::saveState(MSDevice_ToC::getResponseTimeRNG()));
613 13 : MSLane::saveRNGStates(out);
614 13 : out.closeTag();
615 :
616 13 : }
617 :
618 :
619 : /****************************************************************************/
|