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