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 486 : MSStateHandler::MSStateTimeHandler::getTime(const std::string& fileName) {
71 : // build handler and parser
72 486 : MSStateTimeHandler handler;
73 486 : handler.setFileName(fileName);
74 486 : handler.myTime = -1;
75 486 : SUMOSAXReader* parser = XMLSubSys::getSAXReader(handler);
76 : try {
77 960 : 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 91396 : while (parser->parseNext() && handler.myTime != -1);
87 : // clean up
88 469 : if (handler.myTime == -1) {
89 0 : delete parser;
90 0 : throw ProcessError(TLF("Could not parse time from state file '%'", fileName));
91 : }
92 469 : delete parser;
93 469 : return handler.myTime;
94 : }
95 :
96 : void
97 37811 : MSStateHandler::MSStateTimeHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
98 37811 : if (element == SUMO_TAG_SNAPSHOT) {
99 474 : myTime = string2time(attrs.getString(SUMO_ATTR_TIME));
100 : }
101 37811 : }
102 :
103 : // ===========================================================================
104 : // method definitions
105 : // ===========================================================================
106 468 : MSStateHandler::MSStateHandler(const std::string& file, const SUMOTime offset) :
107 : MSRouteHandler(file, true),
108 468 : myOffset(offset),
109 468 : mySegment(nullptr),
110 468 : myCurrentLane(nullptr),
111 468 : myCurrentLink(nullptr),
112 468 : myAttrs(nullptr),
113 468 : myVCAttrs(nullptr),
114 468 : myCFMAttrs(nullptr),
115 468 : myLastParameterised(nullptr),
116 468 : myRemoved(0),
117 468 : myFlowIndex(-1),
118 468 : myConstrainedSignal(nullptr) {
119 468 : myAmLoadingState = true;
120 936 : const std::vector<std::string> vehIDs = OptionsCont::getOptions().getStringVector("load-state.remove-vehicles");
121 : myVehiclesToRemove.insert(vehIDs.begin(), vehIDs.end());
122 468 : myAllowInternalRoutes = true;
123 468 : }
124 :
125 :
126 468 : MSStateHandler::~MSStateHandler() {
127 468 : delete myVCAttrs;
128 468 : }
129 :
130 :
131 : void
132 529 : MSStateHandler::saveState(const std::string& file, SUMOTime step, bool usePrefix) {
133 529 : OutputDevice& out = OutputDevice::getDevice(file, usePrefix);
134 529 : const int statePrecision = OptionsCont::getOptions().getInt("save-state.precision");
135 529 : out.setPrecision(statePrecision);
136 529 : const int defaultPrecision = gPrecision;
137 529 : gPrecision = statePrecision;
138 : std::map<SumoXMLAttr, std::string> attrs;
139 529 : attrs[SUMO_ATTR_VERSION] = VERSION_STRING;
140 529 : attrs[SUMO_ATTR_TIME] = time2string(step);
141 877 : attrs[SUMO_ATTR_TYPE] = MSGlobals::gUseMesoSim ? "meso" : "micro";
142 1058 : if (OptionsCont::getOptions().getBool("save-state.constraints")) {
143 18 : attrs[SUMO_ATTR_CONSTRAINTS] = "1";
144 : }
145 529 : if (MSDriveWay::haveDriveWays()) {
146 48 : attrs[SUMO_ATTR_RAIL] = "1";
147 : }
148 1058 : out.writeXMLHeader("snapshot", "state_file.xsd", attrs);
149 1058 : if (OptionsCont::getOptions().getBool("save-state.rng")) {
150 45 : saveRNGs(out);
151 45 : if (!MSGlobals::gUseMesoSim) {
152 30 : MSNet::getInstance()->getEdgeControl().saveState(out);
153 : }
154 : }
155 : const MSDispatch* dispatcher = MSDevice_Taxi::getDispatchAlgorithm();
156 529 : if (dispatcher != nullptr) {
157 : // save early to pre-empty initialization from loaded persons
158 16 : dispatcher->saveState(out, MSDevice_Taxi::getNextDispatchTime());
159 : }
160 529 : MSRoute::dict_saveState(out);
161 529 : MSNet::getInstance()->getVehicleControl().saveState(out);
162 529 : MSNet::getInstance()->getInsertionControl().saveState(out);
163 1058 : 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 529 : MSVehicleTransfer::getInstance()->saveState(out);
176 18170 : for (MSEdge* const edge : MSEdge::getAllEdges()) {
177 17641 : if (MSGlobals::gUseMesoSim) {
178 24558 : for (MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*edge); s != nullptr; s = s->getNextSegment()) {
179 12140 : s->saveState(out);
180 : }
181 : } else {
182 23978 : for (MSLane* const lane : edge->getLanes()) {
183 12546 : lane->saveState(out);
184 : }
185 : }
186 : }
187 529 : MSNet::getInstance()->getTLSControl().saveState(out);
188 529 : MSRoutingEngine::saveState(out);
189 529 : out.close();
190 529 : gPrecision = defaultPrecision;
191 529 : }
192 :
193 :
194 : void
195 37318 : MSStateHandler::myStartElement(int element, const SUMOSAXAttributes& attrs) {
196 37318 : MSRouteHandler::myStartElement(element, attrs);
197 37316 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
198 37316 : switch (element) {
199 468 : case SUMO_TAG_SNAPSHOT: {
200 468 : myTime = string2time(attrs.getString(SUMO_ATTR_TIME));
201 468 : const std::string& version = attrs.getString(SUMO_ATTR_VERSION);
202 468 : if (version != VERSION_STRING) {
203 477 : WRITE_WARNINGF(TL("State was written with sumo version % (present: %)!"), version, VERSION_STRING);
204 : }
205 : bool ok;
206 468 : if (attrs.getOpt<bool>(SUMO_ATTR_CONSTRAINTS, nullptr, ok, false)) {
207 7 : MSRailSignalConstraint::clearAll();
208 : }
209 468 : 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 45 : case SUMO_TAG_RNGSTATE: {
216 45 : if (attrs.hasAttribute(SUMO_ATTR_DEFAULT)) {
217 90 : RandHelper::loadState(attrs.getString(SUMO_ATTR_DEFAULT));
218 : }
219 45 : if (attrs.hasAttribute(SUMO_ATTR_RNG_ROUTEHANDLER)) {
220 90 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_ROUTEHANDLER), MSRouteHandler::getParsingRNG());
221 : }
222 45 : if (attrs.hasAttribute(SUMO_ATTR_RNG_INSERTIONCONTROL)) {
223 90 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_INSERTIONCONTROL), MSNet::getInstance()->getInsertionControl().getFlowRNG());
224 : }
225 45 : if (attrs.hasAttribute(SUMO_ATTR_RNG_DEVICE)) {
226 90 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DEVICE), MSDevice::getEquipmentRNG());
227 : }
228 45 : if (attrs.hasAttribute(SUMO_ATTR_RNG_DEVICE_BT)) {
229 90 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DEVICE_BT), MSDevice_BTreceiver::getRNG());
230 : }
231 45 : if (attrs.hasAttribute(SUMO_ATTR_RNG_DRIVERSTATE)) {
232 90 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DRIVERSTATE), OUProcess::getRNG());
233 : }
234 45 : if (attrs.hasAttribute(SUMO_ATTR_RNG_DEVICE_TOC)) {
235 90 : RandHelper::loadState(attrs.getString(SUMO_ATTR_RNG_DEVICE_TOC), MSDevice_ToC::getResponseTimeRNG());
236 : }
237 : break;
238 : }
239 2880 : case SUMO_TAG_RNGLANE: {
240 2880 : const int index = attrs.getInt(SUMO_ATTR_INDEX);
241 2880 : const std::string state = attrs.getString(SUMO_ATTR_STATE);
242 2880 : MSLane::loadRNGState(index, state);
243 : break;
244 : }
245 : case SUMO_TAG_EDGECONTROL: {
246 : bool ok;
247 : std::list<MSLane*> activeLanes;
248 30 : const std::vector<std::string>& laneIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_LANES, nullptr, ok, false);
249 94 : for (const std::string& laneID : laneIDs) {
250 64 : MSLane* lane = MSLane::dictionary(laneID);
251 64 : if (lane == nullptr) {
252 0 : throw ProcessError(TLF("Unknown lane '%' in loaded state.", laneID));
253 : }
254 : activeLanes.push_back(lane);
255 : }
256 30 : MSNet::getInstance()->getEdgeControl().setActiveLanes(activeLanes);
257 : break;
258 30 : }
259 191 : case SUMO_TAG_ROUTINGENGINE: {
260 191 : bool ok = true;
261 191 : const SUMOTime lastAdaptation = attrs.get<SUMOTime>(SUMO_ATTR_LAST, nullptr, ok);
262 191 : const int index = attrs.get<int>(SUMO_ATTR_INDEX, nullptr, ok);
263 191 : if (lastAdaptation >= 0) {
264 191 : MSRoutingEngine::initWeightUpdate(lastAdaptation);
265 : }
266 191 : MSRoutingEngine::initEdgeWeights(SVC_PASSENGER, lastAdaptation, index);
267 382 : if (OptionsCont::getOptions().getBool("device.rerouting.bike-speeds")) {
268 0 : MSRoutingEngine::initEdgeWeights(SVC_BICYCLE);
269 : }
270 191 : if (MSGlobals::gUseMesoSim) {
271 3712 : for (const MSEdge* e : MSEdge::getAllEdges()) {
272 9256 : for (MESegment* segment = MSGlobals::gMesoNet->getSegmentForEdge(*e); segment != nullptr; segment = segment->getNextSegment()) {
273 5582 : segment->resetCachedSpeeds();
274 : }
275 : }
276 : }
277 : break;
278 : }
279 1823 : case SUMO_TAG_EDGE: {
280 : #ifdef HAVE_FOX
281 1823 : MSRoutingEngine::loadState(attrs);
282 : #endif
283 1823 : break;
284 : }
285 466 : case SUMO_TAG_DELAY: {
286 466 : if (myVCAttrs != nullptr) {
287 0 : delete myVCAttrs;
288 : }
289 : bool ok;
290 466 : MSNet::getInstance()->setLoaderTime(attrs.getOpt<SUMOTime>(SUMO_ATTR_LOADERTIME, nullptr, ok, 0));
291 466 : 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 717 : case SUMO_TAG_VTYPE: {
304 717 : myLastParameterised = myCurrentVType;
305 717 : break;
306 : }
307 4924 : case SUMO_TAG_VEHICLE: {
308 4924 : myLastParameterised = myVehicleParameter;
309 4924 : myAttrs = attrs.clone();
310 4924 : break;
311 : }
312 6699 : case SUMO_TAG_DEVICE: {
313 6699 : myDeviceAttrs.push_back(attrs.clone());
314 6699 : break;
315 : }
316 90 : case SUMO_TAG_CFM_VARIABLES: {
317 90 : myCFMAttrs = attrs.clone();
318 90 : break;
319 : }
320 182 : case SUMO_TAG_REMINDER: {
321 182 : myReminderAttrs.push_back(attrs.clone());
322 182 : break;
323 : }
324 205 : case SUMO_TAG_VEHICLETRANSFER: {
325 205 : MSVehicleTransfer::getInstance()->loadState(attrs, myOffset, vc);
326 205 : 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 1601 : while (idx-- > 0 && mySegment != nullptr) {
334 494 : 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 600 : case SUMO_TAG_LANE: {
343 : bool ok;
344 600 : const std::string laneID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
345 600 : myCurrentLane = MSLane::dictionary(laneID);
346 600 : if (myCurrentLane == nullptr) {
347 0 : throw ProcessError(TLF("Unknown lane '%' in loaded state.", laneID));
348 : }
349 : break;
350 : }
351 1747 : case SUMO_TAG_VIEWSETTINGS_VEHICLES: {
352 : bool ok;
353 1747 : const std::vector<std::string>& vehIDs = attrs.get<std::vector<std::string> >(SUMO_ATTR_VALUE, nullptr, ok, false);
354 : std::vector<SUMOVehicle*> vehs;
355 3711 : for (const std::string& id : vehIDs) {
356 1964 : SUMOVehicle* v = vc.getVehicle(id);
357 : // vehicle could be removed due to options
358 1964 : if (v != nullptr) {
359 1956 : vehs.push_back(v);
360 : myArrived.erase(v);
361 : }
362 : }
363 1747 : if (MSGlobals::gUseMesoSim) {
364 1165 : 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 1164 : const SUMOTime blockTime = StringUtils::toLong(attrs.getString(SUMO_ATTR_TIME));
368 1164 : const SUMOTime entryBlockTime = StringUtils::toLong(attrs.getString(SUMO_ATTR_BLOCKTIME));
369 1164 : mySegment->loadState(vehs, blockTime - myOffset, entryBlockTime - myOffset, myQueIndex);
370 1164 : myQueIndex++;
371 : } else {
372 582 : myCurrentLane->loadState(vehs);
373 : }
374 : break;
375 1748 : }
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 163 : case SUMO_TAG_PARAM: {
419 : bool ok;
420 163 : const std::string key = attrs.get<std::string>(SUMO_ATTR_KEY, nullptr, ok);
421 : // circumventing empty string test
422 163 : const std::string val = attrs.hasAttribute(SUMO_ATTR_VALUE) ? attrs.getString(SUMO_ATTR_VALUE) : "";
423 : assert(myLastParameterised != 0);
424 163 : if (myLastParameterised != nullptr) {
425 163 : 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 1946 : case SUMO_TAG_TLLOGIC: {
461 : bool ok;
462 1946 : const std::string tlID = attrs.get<std::string>(SUMO_ATTR_ID, nullptr, ok);
463 1946 : const std::string programID = attrs.get<std::string>(SUMO_ATTR_PROGRAMID, tlID.c_str(), ok);
464 1946 : const int phase = attrs.get<int>(SUMO_ATTR_PHASE, tlID.c_str(), ok);
465 1946 : const SUMOTime spentDuration = attrs.get<SUMOTime>(SUMO_ATTR_DURATION, tlID.c_str(), ok);
466 1946 : const bool active = attrs.get<bool>(SUMO_ATTR_ACTIVE, tlID.c_str(), ok);
467 1946 : MSTLLogicControl& tlc = MSNet::getInstance()->getTLSControl();
468 1946 : MSTrafficLightLogic* tl = tlc.get(tlID, programID);
469 1946 : if (tl == nullptr) {
470 8 : if (programID == "online") {
471 24 : WRITE_WARNINGF(TL("Ignoring program '%' for traffic light '%' in loaded state"), programID, tlID);
472 : return;
473 : } else {
474 0 : throw ProcessError("Unknown program '" + programID + "' for traffic light '" + tlID + "'");
475 : }
476 : }
477 1938 : if (phase >= tl->getPhaseNumber()) {
478 0 : throw ProcessError("Invalid phase '" + toString(phase) + "' for traffic light '" + tlID + "'");
479 : }
480 : // might not be set if the phase happens to match and there are multiple programs
481 1938 : tl->loadState(tlc, myTime, phase, spentDuration, active);
482 1938 : if (attrs.hasAttribute(SUMO_ATTR_STATE)) {
483 2 : tl->loadExtraState(attrs.get<std::string>(SUMO_ATTR_STATE, tlID.c_str(), ok));
484 : }
485 : break;
486 : }
487 16 : case SUMO_TAG_DISPATCHER: {
488 16 : bool ok = true;
489 16 : SUMOTime next = attrs.get<SUMOTime>(SUMO_ATTR_NEXT, "dispatcher", ok);
490 16 : MSDevice_Taxi::initDispatch(next);
491 16 : MSDevice_Taxi::getDispatchAlgorithm()->loadState(attrs);
492 : break;
493 : }
494 : default:
495 : break;
496 : }
497 : }
498 :
499 :
500 : void
501 37304 : MSStateHandler::myEndElement(int element) {
502 37304 : MSRouteHandler::myEndElement(element);
503 37297 : switch (element) {
504 219 : case SUMO_TAG_PERSON:
505 : case SUMO_TAG_CONTAINER: {
506 219 : MSTransportableControl& tc = (element == SUMO_TAG_PERSON ? MSNet::getInstance()->getPersonControl() : MSNet::getInstance()->getContainerControl());
507 219 : MSTransportable* transportable = tc.get(myAttrs->getString(SUMO_ATTR_ID));
508 219 : transportable->loadState(myAttrs->getString(SUMO_ATTR_STATE));
509 219 : tc.fixLoadCount(transportable);
510 219 : delete myAttrs;
511 219 : myAttrs = nullptr;
512 219 : break;
513 : }
514 62 : case SUMO_TAG_FLOWSTATE: {
515 62 : MSNet::getInstance()->getInsertionControl().addFlow(myVehicleParameter, myFlowIndex);
516 62 : myVehicleParameter = nullptr;
517 62 : break;
518 : }
519 458 : case SUMO_TAG_SNAPSHOT: {
520 458 : if (myVCAttrs == nullptr) {
521 0 : throw ProcessError(TL("Could not load vehicle control state"));
522 : }
523 458 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
524 458 : vc.setState(myVCAttrs->getInt(SUMO_ATTR_NUMBER),
525 458 : myVCAttrs->getInt(SUMO_ATTR_BEGIN),
526 458 : myVCAttrs->getInt(SUMO_ATTR_END),
527 458 : myVCAttrs->getFloat(SUMO_ATTR_DEPART),
528 458 : myVCAttrs->getFloat(SUMO_ATTR_TIME),
529 458 : myVCAttrs->getFloat(SUMO_ATTR_SPEEDFACTOR),
530 458 : myVCAttrs->getFloat(SUMO_ATTR_DECEL));
531 458 : if (myRemoved > 0) {
532 16 : WRITE_MESSAGEF(TL("Removed % vehicles while loading state."), toString(myRemoved));
533 8 : vc.discountStateRemoved(myRemoved);
534 : }
535 461 : for (SUMOVehicle* v : myArrived) {
536 : // state was created with active option --keep-after-arrival
537 3 : vc.deleteKeptVehicle(v);
538 : }
539 458 : if (!MSGlobals::gUseMesoSim) {
540 3804 : for (MSVehicleControl::constVehIt i = vc.loadedVehBegin(); i != vc.loadedVehEnd(); ++i) {
541 3472 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>((*i).second);
542 3472 : if (microVeh->hasDeparted() && microVeh->getLane() != nullptr) {
543 : // occupancy update must happen after all lane states have been loaded
544 1667 : microVeh->updateBestLanes();
545 : }
546 : }
547 : }
548 458 : MSDevice_Taxi::finalizeLoadState();
549 458 : break;
550 : }
551 : default:
552 : break;
553 : }
554 37297 : if (element != SUMO_TAG_PARAM && myVehicleParameter == nullptr && myCurrentVType == nullptr) {
555 22973 : myLastParameterised = nullptr;
556 : }
557 37297 : }
558 :
559 :
560 : void
561 4924 : MSStateHandler::closeVehicle() {
562 : assert(myVehicleParameter != nullptr);
563 4924 : myVehicleParameter->depart -= myOffset;
564 : // the vehicle was already counted in MSVehicleControl::setState
565 4924 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
566 : // make a copy because myVehicleParameter is reset in closeVehicle()
567 4924 : const std::string vehID = myVehicleParameter->id;
568 : if (myVehiclesToRemove.count(vehID) == 0) {
569 :
570 : // devices that influence simulation behavior must replicate stochastic assignment
571 : // also, setting the parameter avoids extra calls to MSDevice::myEquipmentRNG (which would pollute replication)
572 : std::vector<std::string> deviceNames;
573 11607 : for (auto attrs : myDeviceAttrs) {
574 13382 : deviceNames.push_back(MSDevice::getDeviceName(attrs->getString(SUMO_ATTR_ID)));
575 : }
576 4916 : myVehicleParameter->setParameter(MSDevice::LOADSTATE_DEVICENAMES, toString(deviceNames));
577 4916 : MSRouteHandler::closeVehicle();
578 4915 : SUMOVehicle* v = vc.getVehicle(vehID);
579 : // special case: transportable devices are not assigned by options
580 4915 : if (std::find(deviceNames.begin(), deviceNames.end(), "person") != deviceNames.end()) {
581 27 : dynamic_cast<MSBaseVehicle*>(v)->initTransportableDevice(true);
582 : }
583 4915 : if (std::find(deviceNames.begin(), deviceNames.end(), "container") != deviceNames.end()) {
584 0 : dynamic_cast<MSBaseVehicle*>(v)->initTransportableDevice(false);
585 : }
586 : // clean up added param after initializing devices in closeVehicle
587 4915 : ((SUMOVehicleParameter&)v->getParameter()).unsetParameter(MSDevice::LOADSTATE_DEVICENAMES);
588 : if (v == nullptr) {
589 : throw ProcessError(TLF("Could not load vehicle '%' from state", vehID));
590 : }
591 4915 : v->setChosenSpeedFactor(myAttrs->getFloat(SUMO_ATTR_SPEEDFACTOR));
592 4915 : v->loadState(*myAttrs, myOffset);
593 :
594 4909 : if (v->hasDeparted()) {
595 : // vehicle already departed: disable pre-insertion rerouting and enable regular routing behavior
596 2430 : MSDevice_Routing* routingDevice = static_cast<MSDevice_Routing*>(v->getDevice(typeid(MSDevice_Routing)));
597 : if (routingDevice != nullptr) {
598 1722 : routingDevice->notifyEnter(*v, MSMoveReminder::NOTIFICATION_DEPARTED);
599 : }
600 2430 : MSNet::getInstance()->getInsertionControl().alreadyDeparted(v);
601 2430 : if (MSRailSignalControl::hasInstance()) {
602 : // register route for deadlock prevention (vehicleStateChanged would not be called otherwise)
603 68 : MSRailSignalControl::getInstance().vehicleStateChanged(v, MSNet::VehicleState::NEWROUTE, "loadState");
604 : }
605 2430 : vc.handleTriggeredDepart(v, false);
606 2430 : if (v->hasArrived()) {
607 : myArrived.insert(v);
608 : }
609 : }
610 11593 : while (!myDeviceAttrs.empty()) {
611 6684 : const std::string attrID = myDeviceAttrs.back()->getString(SUMO_ATTR_ID);
612 18085 : for (MSVehicleDevice* const dev : v->getDevices()) {
613 11401 : if (dev->getID() == attrID) {
614 6683 : dev->loadState(*myDeviceAttrs.back());
615 : }
616 : }
617 6684 : delete myDeviceAttrs.back();
618 : myDeviceAttrs.pop_back();
619 : }
620 4909 : bool ok = true;
621 5088 : while (!myReminderAttrs.empty()) {
622 179 : const std::string attrID = myReminderAttrs.back()->getString(SUMO_ATTR_ID);
623 179 : const SUMOTime time = myReminderAttrs.back()->get<SUMOTime>(SUMO_ATTR_TIME, nullptr, ok, false);
624 179 : const double pos = myReminderAttrs.back()->get<double>(SUMO_ATTR_POSITION, nullptr, ok, false);
625 179 : const auto& remDict = MSNet::getInstance()->getDetectorControl().getAllReminders();
626 : auto it = remDict.find(attrID);
627 179 : if (it != remDict.end()) {
628 6 : it->second->loadReminderState(v->getNumericalID(), time, pos);
629 : }
630 179 : delete myReminderAttrs.back();
631 : myReminderAttrs.pop_back();
632 : }
633 4909 : if (myCFMAttrs != nullptr) {
634 : assert(!MSGlobals::gUseMesoSim);
635 90 : MSVehicle* microVeh = dynamic_cast<MSVehicle*>(v);
636 : const MSCFModel::VehicleVariables* vars = microVeh->getCarFollowVariables();
637 90 : if (vars != nullptr) {
638 90 : const_cast<MSCFModel::VehicleVariables*>(vars)->loadState(*myCFMAttrs);
639 : }
640 90 : delete myCFMAttrs;
641 90 : myCFMAttrs = nullptr;
642 : }
643 4916 : } else {
644 8 : const std::string embeddedRouteID = "!" + myVehicleParameter->id;
645 8 : if (MSRoute::hasRoute(embeddedRouteID)) {
646 2 : ConstMSRoutePtr embedded = MSRoute::dictionary(embeddedRouteID);
647 2 : embedded->checkRemoval();
648 : }
649 8 : delete myVehicleParameter;
650 :
651 8 : myVehicleParameter = nullptr;
652 8 : myRemoved++;
653 16 : while (!myDeviceAttrs.empty()) {
654 8 : delete myDeviceAttrs.back();
655 : myDeviceAttrs.pop_back();
656 : }
657 9 : while (!myReminderAttrs.empty()) {
658 1 : delete myReminderAttrs.back();
659 : myReminderAttrs.pop_back();
660 : }
661 : }
662 4917 : delete myAttrs;
663 4917 : }
664 :
665 :
666 : void
667 45 : MSStateHandler::saveRNGs(OutputDevice& out) {
668 45 : out.openTag(SUMO_TAG_RNGSTATE);
669 45 : out.writeAttr(SUMO_ATTR_DEFAULT, RandHelper::saveState());
670 45 : out.writeAttr(SUMO_ATTR_RNG_ROUTEHANDLER, RandHelper::saveState(MSRouteHandler::getParsingRNG()));
671 45 : out.writeAttr(SUMO_ATTR_RNG_INSERTIONCONTROL, RandHelper::saveState(MSNet::getInstance()->getInsertionControl().getFlowRNG()));
672 45 : out.writeAttr(SUMO_ATTR_RNG_DEVICE, RandHelper::saveState(MSDevice::getEquipmentRNG()));
673 45 : out.writeAttr(SUMO_ATTR_RNG_DEVICE_BT, RandHelper::saveState(MSDevice_BTreceiver::getRNG()));
674 45 : out.writeAttr(SUMO_ATTR_RNG_DRIVERSTATE, RandHelper::saveState(OUProcess::getRNG()));
675 45 : out.writeAttr(SUMO_ATTR_RNG_DEVICE_TOC, RandHelper::saveState(MSDevice_ToC::getResponseTimeRNG()));
676 45 : MSLane::saveRNGStates(out);
677 45 : out.closeTag();
678 :
679 45 : }
680 :
681 :
682 : /****************************************************************************/
|