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