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