Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-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 MSNet.cpp
15 : /// @author Christian Roessel
16 : /// @author Daniel Krajzewicz
17 : /// @author Jakob Erdmann
18 : /// @author Clemens Honomichl
19 : /// @author Eric Nicolay
20 : /// @author Mario Krumnow
21 : /// @author Michael Behrisch
22 : /// @author Christoph Sommer
23 : /// @date Tue, 06 Mar 2001
24 : ///
25 : // The simulated network and simulation performer
26 : /****************************************************************************/
27 : #include <config.h>
28 :
29 : #ifdef HAVE_VERSION_H
30 : #include <version.h>
31 : #endif
32 :
33 : #include <string>
34 : #include <iostream>
35 : #include <sstream>
36 : #include <typeinfo>
37 : #include <algorithm>
38 : #include <cassert>
39 : #include <vector>
40 : #include <ctime>
41 :
42 : #ifdef HAVE_FOX
43 : #include <utils/common/ScopedLocker.h>
44 : #endif
45 : #include <utils/common/MsgHandler.h>
46 : #include <utils/common/ToString.h>
47 : #include <utils/common/SysUtils.h>
48 : #include <utils/common/UtilExceptions.h>
49 : #include <utils/common/WrappingCommand.h>
50 : #include <utils/common/SystemFrame.h>
51 : #include <utils/geom/GeoConvHelper.h>
52 : #include <utils/iodevices/OutputDevice_File.h>
53 : #include <utils/iodevices/OutputDevice.h>
54 : #include <utils/options/OptionsCont.h>
55 : #include <utils/options/OptionsIO.h>
56 : #include <utils/shapes/ShapeContainer.h>
57 : #include <utils/router/DijkstraRouter.h>
58 : #include <utils/router/AStarRouter.h>
59 : #include <utils/router/IntermodalRouter.h>
60 : #include <utils/router/PedestrianRouter.h>
61 : #include <utils/vehicle/SUMORouteLoaderControl.h>
62 : #include <utils/vehicle/SUMORouteLoader.h>
63 : #include <utils/vehicle/SUMOVehicleParserHelper.h>
64 : #include <utils/xml/XMLSubSys.h>
65 : #include <traci-server/TraCIServer.h>
66 : #include <libsumo/Helper.h>
67 : #include <libsumo/Simulation.h>
68 : #include <mesosim/MELoop.h>
69 : #include <mesosim/MESegment.h>
70 : #include <microsim/output/MSDetectorControl.h>
71 : #include <microsim/MSVehicleTransfer.h>
72 : #include <microsim/devices/MSRoutingEngine.h>
73 : #include <microsim/devices/MSDevice_Vehroutes.h>
74 : #include <microsim/devices/MSDevice_Tripinfo.h>
75 : #include <microsim/devices/MSDevice_BTsender.h>
76 : #include <microsim/devices/MSDevice_SSM.h>
77 : #include <microsim/devices/MSDevice_ElecHybrid.h>
78 : #include <microsim/devices/MSDevice_ToC.h>
79 : #include <microsim/devices/MSDevice_Taxi.h>
80 : #include <microsim/output/MSBatteryExport.h>
81 : #include <microsim/output/MSChargingStationExport.h>
82 : #include <microsim/output/MSElecHybridExport.h>
83 : #include <microsim/output/MSEmissionExport.h>
84 : #include <microsim/output/MSFCDExport.h>
85 : #include <microsim/output/MSFullExport.h>
86 : #include <microsim/output/MSQueueExport.h>
87 : #include <microsim/output/MSVTKExport.h>
88 : #include <microsim/output/MSXMLRawOut.h>
89 : #include <microsim/output/MSAmitranTrajectories.h>
90 : #include <microsim/output/MSStopOut.h>
91 : #include <microsim/transportables/MSPModel.h>
92 : #include <microsim/transportables/MSPerson.h>
93 : #include <microsim/traffic_lights/MSTrafficLightLogic.h>
94 : #include <microsim/transportables/MSTransportableControl.h>
95 : #include <microsim/traffic_lights/MSRailSignal.h>
96 : #include <microsim/traffic_lights/MSRailSignalConstraint.h>
97 : #include <microsim/traffic_lights/MSRailSignalControl.h>
98 : #include <microsim/traffic_lights/MSTLLogicControl.h>
99 : #include <microsim/traffic_lights/MSDriveWay.h>
100 : #include <microsim/trigger/MSCalibrator.h>
101 : #include <microsim/trigger/MSChargingStation.h>
102 : #include <microsim/trigger/MSLaneSpeedTrigger.h>
103 : #include <microsim/trigger/MSOverheadWire.h>
104 : #include <microsim/trigger/MSTriggeredRerouter.h>
105 : #include <utils/router/FareModul.h>
106 : #include <netload/NLBuilder.h>
107 :
108 : #include "MSEdgeControl.h"
109 : #include "MSJunctionControl.h"
110 : #include "MSInsertionControl.h"
111 : #include "MSDynamicShapeUpdater.h"
112 : #include "MSEventControl.h"
113 : #include "MSEdge.h"
114 : #include "MSJunction.h"
115 : #include "MSJunctionLogic.h"
116 : #include "MSLane.h"
117 : #include "MSVehicleControl.h"
118 : #include "MSVehicleTransfer.h"
119 : #include "MSRoute.h"
120 : #include "MSGlobals.h"
121 : #include "MSEdgeWeightsStorage.h"
122 : #include "MSStateHandler.h"
123 : #include "MSFrame.h"
124 : #include "MSParkingArea.h"
125 : #include "MSStoppingPlace.h"
126 : #include "MSNet.h"
127 :
128 :
129 : // ===========================================================================
130 : // debug constants
131 : // ===========================================================================
132 : //#define DEBUG_SIMSTEP
133 :
134 :
135 : // ===========================================================================
136 : // static member definitions
137 : // ===========================================================================
138 : MSNet* MSNet::myInstance = nullptr;
139 :
140 : const std::string MSNet::STAGE_EVENTS("events");
141 : const std::string MSNet::STAGE_MOVEMENTS("move");
142 : const std::string MSNet::STAGE_LANECHANGE("laneChange");
143 : const std::string MSNet::STAGE_INSERTIONS("insertion");
144 : const std::string MSNet::STAGE_REMOTECONTROL("remoteControl");
145 :
146 : const NamedObjectCont<MSStoppingPlace*> MSNet::myEmptyStoppingPlaceCont;
147 : const std::vector<MSStoppingPlace*> MSNet::myEmptyStoppingPlaceVector;
148 :
149 : // ===========================================================================
150 : // static member method definitions
151 : // ===========================================================================
152 : double
153 336 : MSNet::getEffort(const MSEdge* const e, const SUMOVehicle* const v, double t) {
154 : double value;
155 336 : const MSVehicle* const veh = dynamic_cast<const MSVehicle* const>(v);
156 336 : if (veh != nullptr && veh->getWeightsStorage().retrieveExistingEffort(e, t, value)) {
157 2 : return value;
158 : }
159 334 : if (getInstance()->getWeightsStorage().retrieveExistingEffort(e, t, value)) {
160 2 : return value;
161 : }
162 : return 0;
163 : }
164 :
165 :
166 : double
167 6629984 : MSNet::getTravelTime(const MSEdge* const e, const SUMOVehicle* const v, double t) {
168 : double value;
169 6629984 : const MSVehicle* const veh = dynamic_cast<const MSVehicle* const>(v);
170 6629006 : if (veh != nullptr && veh->getWeightsStorage().retrieveExistingTravelTime(e, t, value)) {
171 527 : return value;
172 : }
173 6629457 : if (getInstance()->getWeightsStorage().retrieveExistingTravelTime(e, t, value)) {
174 177 : return value;
175 : }
176 6629280 : if (veh != nullptr && veh->getRoutingMode() == libsumo::ROUTING_MODE_AGGREGATED_CUSTOM) {
177 2965 : return MSRoutingEngine::getEffortExtra(e, v, t);
178 : }
179 6626315 : return e->getMinimumTravelTime(v);
180 : }
181 :
182 :
183 : // ---------------------------------------------------------------------------
184 : // MSNet - methods
185 : // ---------------------------------------------------------------------------
186 : MSNet*
187 5423472977 : MSNet::getInstance(void) {
188 5423472977 : if (myInstance != nullptr) {
189 5423472932 : return myInstance;
190 : }
191 90 : throw ProcessError(TL("A network was not yet constructed."));
192 : }
193 :
194 : void
195 41242 : MSNet::initStatic() {
196 41242 : gRoutingPreferences = false;
197 41242 : MSDriveWay::init();
198 41242 : }
199 :
200 : void
201 40631 : MSNet::cleanupStatic() {
202 40631 : if (!MSGlobals::gUseMesoSim) {
203 34759 : MSVehicle::Influencer::cleanup();
204 : }
205 40631 : }
206 :
207 :
208 41242 : MSNet::MSNet(MSVehicleControl* vc, MSEventControl* beginOfTimestepEvents,
209 : MSEventControl* endOfTimestepEvents,
210 : MSEventControl* insertionEvents,
211 41242 : ShapeContainer* shapeCont):
212 41242 : myAmInterrupted(false),
213 41242 : myVehiclesMoved(0),
214 41242 : myPersonsMoved(0),
215 41242 : myHavePermissions(false),
216 41242 : myHasInternalLinks(false),
217 41242 : myJunctionHigherSpeeds(false),
218 41242 : myHasElevation(false),
219 41242 : myHasPedestrianNetwork(false),
220 41242 : myHasBidiEdges(false),
221 41242 : myEdgeDataEndTime(-1),
222 41242 : myDynamicShapeUpdater(nullptr) {
223 41242 : if (myInstance != nullptr) {
224 0 : throw ProcessError(TL("A network was already constructed."));
225 : }
226 41242 : OptionsCont& oc = OptionsCont::getOptions();
227 41242 : myStep = string2time(oc.getString("begin"));
228 41242 : myMaxTeleports = oc.getInt("max-num-teleports");
229 41242 : myLogExecutionTime = !oc.getBool("no-duration-log");
230 41242 : myLogStepNumber = !oc.getBool("no-step-log");
231 41242 : myLogStepPeriod = oc.getInt("step-log.period");
232 164968 : myInserter = new MSInsertionControl(*vc, string2time(oc.getString("max-depart-delay")), oc.getBool("eager-insert"), oc.getInt("max-num-vehicles"),
233 164968 : string2time(oc.getString("random-depart-offset")));
234 41242 : myVehicleControl = vc;
235 41242 : myDetectorControl = new MSDetectorControl();
236 41242 : myEdges = nullptr;
237 41242 : myJunctions = nullptr;
238 41242 : myRouteLoaders = nullptr;
239 41242 : myLogics = nullptr;
240 41242 : myPersonControl = nullptr;
241 41242 : myContainerControl = nullptr;
242 41242 : myEdgeWeights = nullptr;
243 41242 : myShapeContainer = shapeCont == nullptr ? new ShapeContainer() : shapeCont;
244 :
245 41242 : myBeginOfTimestepEvents = beginOfTimestepEvents;
246 41242 : myEndOfTimestepEvents = endOfTimestepEvents;
247 41242 : myInsertionEvents = insertionEvents;
248 41242 : myLanesRTree.first = false;
249 :
250 41242 : if (MSGlobals::gUseMesoSim) {
251 11940 : MSGlobals::gMesoNet = new MELoop(string2time(oc.getString("meso-recheck")));
252 : }
253 41242 : myInstance = this;
254 41242 : initStatic();
255 41242 : }
256 :
257 :
258 : void
259 40768 : MSNet::closeBuilding(const OptionsCont& oc, MSEdgeControl* edges, MSJunctionControl* junctions,
260 : SUMORouteLoaderControl* routeLoaders,
261 : MSTLLogicControl* tlc,
262 : std::vector<SUMOTime> stateDumpTimes,
263 : std::vector<std::string> stateDumpFiles,
264 : bool hasInternalLinks,
265 : bool junctionHigherSpeeds,
266 : const MMVersion& version) {
267 40768 : myEdges = edges;
268 40768 : myJunctions = junctions;
269 40768 : myRouteLoaders = routeLoaders;
270 40768 : myLogics = tlc;
271 : // save the time the network state shall be saved at
272 40768 : myStateDumpTimes = stateDumpTimes;
273 40768 : myStateDumpFiles = stateDumpFiles;
274 40768 : myStateDumpPeriod = string2time(oc.getString("save-state.period"));
275 40768 : myStateDumpPrefix = oc.getString("save-state.prefix");
276 40768 : myStateDumpSuffix = oc.getString("save-state.suffix");
277 :
278 : // initialise performance computation
279 40768 : mySimBeginMillis = SysUtils::getCurrentMillis();
280 40768 : myTraCIMillis = 0;
281 40768 : myHasInternalLinks = hasInternalLinks;
282 40768 : myJunctionHigherSpeeds = junctionHigherSpeeds;
283 40768 : myHasElevation = checkElevation();
284 40768 : myHasPedestrianNetwork = checkWalkingarea();
285 40768 : myHasBidiEdges = checkBidiEdges();
286 : myVersion = version;
287 40768 : if ((!MSGlobals::gUsingInternalLanes || !myHasInternalLinks)
288 17473 : && MSGlobals::gWeightsSeparateTurns > 0) {
289 20 : throw ProcessError(TL("Option weights.separate-turns is only supported when simulating with internal lanes"));
290 : }
291 40758 : }
292 :
293 :
294 72851 : MSNet::~MSNet() {
295 40631 : cleanupStatic();
296 : // delete controls
297 40631 : delete myJunctions;
298 40631 : delete myDetectorControl;
299 : // delete mean data
300 40631 : delete myEdges;
301 40631 : delete myInserter;
302 40631 : myInserter = nullptr;
303 40631 : delete myLogics;
304 40631 : delete myRouteLoaders;
305 40631 : if (myPersonControl != nullptr) {
306 8069 : delete myPersonControl;
307 8069 : myPersonControl = nullptr; // just to have that clear for later cleanups
308 : }
309 40631 : if (myContainerControl != nullptr) {
310 1950 : delete myContainerControl;
311 1950 : myContainerControl = nullptr; // just to have that clear for later cleanups
312 : }
313 40631 : delete myVehicleControl; // must happen after deleting transportables
314 : // delete events late so that vehicles can get rid of references first
315 40631 : delete myBeginOfTimestepEvents;
316 40631 : myBeginOfTimestepEvents = nullptr;
317 40631 : delete myEndOfTimestepEvents;
318 40631 : myEndOfTimestepEvents = nullptr;
319 40631 : delete myInsertionEvents;
320 40631 : myInsertionEvents = nullptr;
321 40631 : delete myShapeContainer;
322 40631 : delete myEdgeWeights;
323 41981 : for (auto& router : myRouterTT) {
324 1350 : delete router.second;
325 : }
326 : myRouterTT.clear();
327 40642 : for (auto& router : myRouterEffort) {
328 11 : delete router.second;
329 : }
330 : myRouterEffort.clear();
331 43452 : for (auto& router : myPedestrianRouter) {
332 2821 : delete router.second;
333 : }
334 : myPedestrianRouter.clear();
335 44550 : for (auto& router : myIntermodalRouter) {
336 3919 : delete router.second;
337 : }
338 : myIntermodalRouter.clear();
339 : myLanesRTree.second.RemoveAll();
340 40631 : clearAll();
341 40631 : if (MSGlobals::gUseMesoSim) {
342 5872 : delete MSGlobals::gMesoNet;
343 : }
344 40631 : myInstance = nullptr;
345 154113 : }
346 :
347 :
348 : void
349 217 : MSNet::addRestriction(const std::string& id, const SUMOVehicleClass svc, const double speed) {
350 217 : myRestrictions[id][svc] = speed;
351 217 : }
352 :
353 :
354 : const std::map<SUMOVehicleClass, double>*
355 2062576 : MSNet::getRestrictions(const std::string& id) const {
356 : std::map<std::string, std::map<SUMOVehicleClass, double> >::const_iterator i = myRestrictions.find(id);
357 2062576 : if (i == myRestrictions.end()) {
358 : return nullptr;
359 : }
360 1094 : return &i->second;
361 : }
362 :
363 :
364 : double
365 3311 : MSNet::getPreference(const std::string& routingType, const SUMOVTypeParameter& pars) const {
366 3311 : if (gRoutingPreferences) {
367 3311 : auto it = myVTypePreferences.find(pars.id);
368 3311 : if (it != myVTypePreferences.end()) {
369 : auto it2 = it->second.find(routingType);
370 224 : if (it2 != it->second.end()) {
371 56 : return it2->second;
372 : }
373 : }
374 : auto it3 = myVClassPreferences.find(pars.vehicleClass);
375 3255 : if (it3 != myVClassPreferences.end()) {
376 : auto it4 = it3->second.find(routingType);
377 336 : if (it4 != it3->second.end()) {
378 84 : return it4->second;
379 : }
380 : }
381 : // fallback to generel preferences
382 3171 : it = myVTypePreferences.find("");
383 3171 : if (it != myVTypePreferences.end()) {
384 : auto it2 = it->second.find(routingType);
385 1995 : if (it2 != it->second.end()) {
386 336 : return it2->second;
387 : }
388 : }
389 : }
390 : return 1;
391 : }
392 :
393 :
394 : void
395 28 : MSNet::addPreference(const std::string& routingType, SUMOVehicleClass svc, double prio) {
396 28 : myVClassPreferences[svc][routingType] = prio;
397 28 : gRoutingPreferences = true;
398 28 : }
399 :
400 :
401 : void
402 56 : MSNet::addPreference(const std::string& routingType, std::string vType, double prio) {
403 56 : myVTypePreferences[vType][routingType] = prio;
404 56 : gRoutingPreferences = true;
405 56 : }
406 :
407 : void
408 24 : MSNet::addMesoType(const std::string& typeID, const MESegment::MesoEdgeType& edgeType) {
409 24 : myMesoEdgeTypes[typeID] = edgeType;
410 24 : }
411 :
412 : const MESegment::MesoEdgeType&
413 784096 : MSNet::getMesoType(const std::string& typeID) {
414 : if (myMesoEdgeTypes.count(typeID) == 0) {
415 : // init defaults
416 6432 : const OptionsCont& oc = OptionsCont::getOptions();
417 : MESegment::MesoEdgeType edgeType;
418 6432 : edgeType.tauff = string2time(oc.getString("meso-tauff"));
419 6432 : edgeType.taufj = string2time(oc.getString("meso-taufj"));
420 6432 : edgeType.taujf = string2time(oc.getString("meso-taujf"));
421 6432 : edgeType.taujj = string2time(oc.getString("meso-taujj"));
422 6432 : edgeType.jamThreshold = oc.getFloat("meso-jam-threshold");
423 6432 : edgeType.junctionControl = oc.getBool("meso-junction-control");
424 6432 : edgeType.tlsPenalty = oc.getFloat("meso-tls-penalty");
425 6432 : edgeType.tlsFlowPenalty = oc.getFloat("meso-tls-flow-penalty");
426 6432 : edgeType.minorPenalty = string2time(oc.getString("meso-minor-penalty"));
427 6432 : edgeType.overtaking = oc.getBool("meso-overtaking");
428 6432 : edgeType.edgeLength = oc.getFloat("meso-edgelength");
429 6432 : myMesoEdgeTypes[typeID] = edgeType;
430 : }
431 784096 : return myMesoEdgeTypes[typeID];
432 : }
433 :
434 :
435 : bool
436 7599040 : MSNet::hasFlow(const std::string& id) const {
437 : // inserter is deleted at the end of the simulation
438 7599040 : return myInserter != nullptr && myInserter->hasFlow(id);
439 : }
440 :
441 :
442 : MSNet::SimulationState
443 30818 : MSNet::simulate(SUMOTime start, SUMOTime stop) {
444 : // report the begin when wished
445 61636 : WRITE_MESSAGEF(TL("Simulation version % started with time: %."), VERSION_STRING, time2string(start));
446 : // the simulation loop
447 : SimulationState state = SIMSTATE_RUNNING;
448 : // state loading may have changed the start time so we need to reinit it
449 30818 : myStep = start;
450 : int numSteps = 0;
451 : bool doStepLog = false;
452 47490727 : while (state == SIMSTATE_RUNNING) {
453 47460228 : doStepLog = myLogStepNumber && (numSteps % myLogStepPeriod == 0);
454 : if (doStepLog) {
455 113 : preSimStepOutput();
456 : }
457 47460228 : simulationStep();
458 47459909 : if (doStepLog) {
459 113 : postSimStepOutput();
460 : }
461 47459909 : state = adaptToState(simulationState(stop));
462 : #ifdef DEBUG_SIMSTEP
463 : std::cout << SIMTIME << " MSNet::simulate(" << start << ", " << stop << ")"
464 : << "\n simulation state: " << getStateMessage(state)
465 : << std::endl;
466 : #endif
467 47459909 : numSteps++;
468 : }
469 30499 : if (myLogStepNumber && !doStepLog) {
470 : // ensure some output on the last step
471 16 : preSimStepOutput();
472 16 : postSimStepOutput();
473 : }
474 : // exit simulation loop
475 30499 : if (myLogStepNumber) {
476 : // start new line for final verbose output
477 20 : std::cout << "\n";
478 : }
479 30499 : closeSimulation(start, getStateMessage(state));
480 30499 : return state;
481 : }
482 :
483 :
484 : void
485 57123777 : MSNet::loadRoutes() {
486 57123777 : myRouteLoaders->loadNext(myStep);
487 57123193 : }
488 :
489 :
490 : const std::string
491 12767 : MSNet::generateStatistics(const SUMOTime start, const long now) {
492 12767 : std::ostringstream msg;
493 12767 : if (myLogExecutionTime) {
494 12449 : const long duration = now - mySimBeginMillis;
495 : // print performance notice
496 24898 : msg << "Performance:\n" << " Duration: " << elapsedMs2string(duration) << "\n";
497 12449 : if (duration != 0) {
498 12279 : if (TraCIServer::getInstance() != nullptr) {
499 4323 : msg << " TraCI-Duration: " << elapsedMs2string(myTraCIMillis) << "\n";
500 : }
501 12279 : msg << " Real time factor: " << (STEPS2TIME(myStep - start) * 1000. / (double)duration) << "\n";
502 : msg.setf(std::ios::fixed, std::ios::floatfield); // use decimal format
503 : msg.setf(std::ios::showpoint); // print decimal point
504 12279 : msg << " UPS: " << ((double)myVehiclesMoved / ((double)duration / 1000)) << "\n";
505 12279 : if (myPersonsMoved > 0) {
506 2345 : msg << " UPS-Persons: " << ((double)myPersonsMoved / ((double)duration / 1000)) << "\n";
507 : }
508 : }
509 : // print vehicle statistics
510 12449 : const std::string vehDiscardNotice = ((myVehicleControl->getLoadedVehicleNo() != myVehicleControl->getDepartedVehicleNo()) ?
511 16421 : " (Loaded: " + toString(myVehicleControl->getLoadedVehicleNo()) + ")" : "");
512 : msg << "Vehicles:\n"
513 12449 : << " Inserted: " << myVehicleControl->getDepartedVehicleNo() << vehDiscardNotice << "\n"
514 24898 : << " Running: " << myVehicleControl->getRunningVehicleNo() << "\n"
515 24898 : << " Waiting: " << myInserter->getWaitingVehicleNo() << "\n";
516 :
517 12449 : if (myVehicleControl->getTeleportCount() > 0 || myVehicleControl->getCollisionCount() > 0) {
518 : // print optional teleport statistics
519 : std::vector<std::string> reasons;
520 652 : if (myVehicleControl->getCollisionCount() > 0) {
521 634 : reasons.push_back("Collisions: " + toString(myVehicleControl->getCollisionCount()));
522 : }
523 652 : if (myVehicleControl->getTeleportsJam() > 0) {
524 396 : reasons.push_back("Jam: " + toString(myVehicleControl->getTeleportsJam()));
525 : }
526 652 : if (myVehicleControl->getTeleportsYield() > 0) {
527 190 : reasons.push_back("Yield: " + toString(myVehicleControl->getTeleportsYield()));
528 : }
529 652 : if (myVehicleControl->getTeleportsWrongLane() > 0) {
530 254 : reasons.push_back("Wrong Lane: " + toString(myVehicleControl->getTeleportsWrongLane()));
531 : }
532 1956 : msg << " Teleports: " << myVehicleControl->getTeleportCount() << " (" << joinToString(reasons, ", ") << ")\n";
533 652 : }
534 12449 : if (myVehicleControl->getEmergencyStops() > 0) {
535 61 : msg << " Emergency Stops: " << myVehicleControl->getEmergencyStops() << "\n";
536 : }
537 12449 : if (myVehicleControl->getEmergencyBrakingCount() > 0) {
538 292 : msg << " Emergency Braking: " << myVehicleControl->getEmergencyBrakingCount() << "\n";
539 : }
540 12449 : if (myPersonControl != nullptr && myPersonControl->getLoadedNumber() > 0) {
541 2394 : const std::string discardNotice = ((myPersonControl->getLoadedNumber() != myPersonControl->getDepartedNumber()) ?
542 2751 : " (Loaded: " + toString(myPersonControl->getLoadedNumber()) + ")" : "");
543 : msg << "Persons:\n"
544 2394 : << " Inserted: " << myPersonControl->getDepartedNumber() << discardNotice << "\n"
545 4788 : << " Running: " << myPersonControl->getRunningNumber() << "\n";
546 2394 : if (myPersonControl->getJammedNumber() > 0) {
547 54 : msg << " Jammed: " << myPersonControl->getJammedNumber() << "\n";
548 : }
549 2394 : if (myPersonControl->getTeleportCount() > 0) {
550 : std::vector<std::string> reasons;
551 7 : if (myPersonControl->getTeleportsAbortWait() > 0) {
552 0 : reasons.push_back("Abort Wait: " + toString(myPersonControl->getTeleportsAbortWait()));
553 : }
554 7 : if (myPersonControl->getTeleportsWrongDest() > 0) {
555 14 : reasons.push_back("Wrong Dest: " + toString(myPersonControl->getTeleportsWrongDest()));
556 : }
557 21 : msg << " Teleports: " << myPersonControl->getTeleportCount() << " (" << joinToString(reasons, ", ") << ")\n";
558 7 : }
559 : }
560 12449 : if (myContainerControl != nullptr && myContainerControl->getLoadedNumber() > 0) {
561 76 : const std::string discardNotice = ((myContainerControl->getLoadedNumber() != myContainerControl->getDepartedNumber()) ?
562 76 : " (Loaded: " + toString(myContainerControl->getLoadedNumber()) + ")" : "");
563 : msg << "Containers:\n"
564 76 : << " Inserted: " << myContainerControl->getDepartedNumber() << "\n"
565 152 : << " Running: " << myContainerControl->getRunningNumber() << "\n";
566 76 : if (myContainerControl->getJammedNumber() > 0) {
567 0 : msg << " Jammed: " << myContainerControl->getJammedNumber() << "\n";
568 : }
569 76 : if (myContainerControl->getTeleportCount() > 0) {
570 : std::vector<std::string> reasons;
571 0 : if (myContainerControl->getTeleportsAbortWait() > 0) {
572 0 : reasons.push_back("Abort Wait: " + toString(myContainerControl->getTeleportsAbortWait()));
573 : }
574 0 : if (myContainerControl->getTeleportsWrongDest() > 0) {
575 0 : reasons.push_back("Wrong Dest: " + toString(myContainerControl->getTeleportsWrongDest()));
576 : }
577 0 : msg << " Teleports: " << myContainerControl->getTeleportCount() << " (" << joinToString(reasons, ", ") << ")\n";
578 0 : }
579 : }
580 : }
581 25534 : if (OptionsCont::getOptions().getBool("duration-log.statistics")) {
582 6196 : msg << MSDevice_Tripinfo::printStatistics();
583 : }
584 : std::string result = msg.str();
585 : result.erase(result.end() - 1);
586 12767 : return result;
587 12767 : }
588 :
589 :
590 : void
591 10356 : MSNet::writeCollisions() const {
592 20712 : OutputDevice& od = OutputDevice::getDeviceByOption("collision-output");
593 10520 : for (const auto& item : myCollisions) {
594 328 : for (const auto& c : item.second) {
595 164 : if (c.time != SIMSTEP) {
596 19 : continue;
597 : }
598 290 : od.openTag("collision");
599 290 : od.writeAttr("time", time2string(getCurrentTimeStep()));
600 145 : od.writeAttr("type", c.type);
601 145 : od.writeAttr("lane", c.lane->getID());
602 145 : od.writeAttr("pos", c.pos);
603 145 : od.writeAttr("collider", item.first);
604 145 : od.writeAttr("victim", c.victim);
605 145 : od.writeAttr("colliderType", c.colliderType);
606 145 : od.writeAttr("victimType", c.victimType);
607 145 : od.writeAttr("colliderSpeed", c.colliderSpeed);
608 145 : od.writeAttr("victimSpeed", c.victimSpeed);
609 145 : od.writeAttr("colliderFront", c.colliderFront);
610 145 : od.writeAttr("colliderBack", c.colliderBack);
611 145 : od.writeAttr("victimFront", c.victimFront);
612 145 : od.writeAttr("victimBack", c.victimBack);
613 290 : od.closeTag();
614 : }
615 : }
616 10356 : }
617 :
618 :
619 : void
620 376 : MSNet::writeStatistics(const SUMOTime start, const long now) const {
621 376 : const long duration = now - mySimBeginMillis;
622 752 : OutputDevice& od = OutputDevice::getDeviceByOption("statistic-output");
623 376 : od.setExpectedAttributes(0);
624 376 : od.openTag("performance");
625 752 : od.writeAttr("clockBegin", time2string(mySimBeginMillis));
626 752 : od.writeAttr("clockEnd", time2string(now));
627 752 : od.writeAttr("clockDuration", time2string(duration));
628 752 : od.writeAttr("traciDuration", time2string(myTraCIMillis));
629 376 : od.writeAttr("realTimeFactor", duration != 0 ? (double)(myStep - start) / (double)duration : -1);
630 376 : od.writeAttr("vehicleUpdatesPerSecond", duration != 0 ? (double)myVehiclesMoved / ((double)duration / 1000) : -1);
631 376 : od.writeAttr("personUpdatesPerSecond", duration != 0 ? (double)myPersonsMoved / ((double)duration / 1000) : -1);
632 752 : od.writeAttr("begin", time2string(start));
633 752 : od.writeAttr("end", time2string(myStep));
634 752 : od.writeAttr("duration", time2string(myStep - start));
635 376 : od.closeTag();
636 376 : od.openTag("vehicles");
637 376 : od.writeAttr("loaded", myVehicleControl->getLoadedVehicleNo());
638 376 : od.writeAttr("inserted", myVehicleControl->getDepartedVehicleNo());
639 376 : od.writeAttr("running", myVehicleControl->getRunningVehicleNo());
640 376 : od.writeAttr("waiting", myInserter->getWaitingVehicleNo());
641 376 : od.closeTag();
642 376 : od.openTag("teleports");
643 376 : od.writeAttr("total", myVehicleControl->getTeleportCount());
644 376 : od.writeAttr("jam", myVehicleControl->getTeleportsJam());
645 376 : od.writeAttr("yield", myVehicleControl->getTeleportsYield());
646 376 : od.writeAttr("wrongLane", myVehicleControl->getTeleportsWrongLane());
647 376 : od.closeTag();
648 376 : od.openTag("safety");
649 376 : od.writeAttr("collisions", myVehicleControl->getCollisionCount());
650 376 : od.writeAttr("emergencyStops", myVehicleControl->getEmergencyStops());
651 376 : od.writeAttr("emergencyBraking", myVehicleControl->getEmergencyBrakingCount());
652 376 : od.closeTag();
653 376 : od.openTag("persons");
654 382 : od.writeAttr("loaded", myPersonControl != nullptr ? myPersonControl->getLoadedNumber() : 0);
655 382 : od.writeAttr("running", myPersonControl != nullptr ? myPersonControl->getRunningNumber() : 0);
656 382 : od.writeAttr("jammed", myPersonControl != nullptr ? myPersonControl->getJammedNumber() : 0);
657 376 : od.closeTag();
658 376 : od.openTag("personTeleports");
659 382 : od.writeAttr("total", myPersonControl != nullptr ? myPersonControl->getTeleportCount() : 0);
660 382 : od.writeAttr("abortWait", myPersonControl != nullptr ? myPersonControl->getTeleportsAbortWait() : 0);
661 382 : od.writeAttr("wrongDest", myPersonControl != nullptr ? myPersonControl->getTeleportsWrongDest() : 0);
662 376 : od.closeTag();
663 597 : if (OptionsCont::getOptions().isSet("tripinfo-output") || OptionsCont::getOptions().getBool("duration-log.statistics")) {
664 264 : MSDevice_Tripinfo::writeStatistics(od);
665 : }
666 376 : }
667 :
668 :
669 : void
670 57122630 : MSNet::writeSummaryOutput(bool finalStep) {
671 : // summary output
672 57122630 : const OptionsCont& oc = OptionsCont::getOptions();
673 57122630 : const bool hasOutput = oc.isSet("summary-output");
674 57122630 : const bool hasPersonOutput = oc.isSet("person-summary-output");
675 57122630 : if (hasOutput || hasPersonOutput) {
676 526290 : const SUMOTime period = string2time(oc.getString("summary-output.period"));
677 526290 : const SUMOTime begin = string2time(oc.getString("begin"));
678 526290 : if ((period > 0 && (myStep - begin) % period != 0 && !finalStep)
679 : // it's the final step but we already wrote output
680 525370 : || (finalStep && (period <= 0 || (myStep - begin) % period == 0))) {
681 : return;
682 : }
683 : }
684 524853 : if (hasOutput) {
685 520101 : OutputDevice& od = OutputDevice::getDeviceByOption("summary-output");
686 520101 : int departedVehiclesNumber = myVehicleControl->getDepartedVehicleNo();
687 520101 : const double meanWaitingTime = departedVehiclesNumber != 0 ? myVehicleControl->getTotalDepartureDelay() / (double) departedVehiclesNumber : -1.;
688 : int endedVehicleNumber = myVehicleControl->getEndedVehicleNo();
689 520101 : const double meanTravelTime = endedVehicleNumber != 0 ? myVehicleControl->getTotalTravelTime() / (double) endedVehicleNumber : -1.;
690 520101 : od.openTag("step");
691 1040202 : od.writeAttr("time", time2string(myStep));
692 520101 : od.writeAttr("loaded", myVehicleControl->getLoadedVehicleNo());
693 520101 : od.writeAttr("inserted", myVehicleControl->getDepartedVehicleNo());
694 520101 : od.writeAttr("running", myVehicleControl->getRunningVehicleNo());
695 520101 : od.writeAttr("waiting", myInserter->getWaitingVehicleNo());
696 520101 : od.writeAttr("ended", myVehicleControl->getEndedVehicleNo());
697 520101 : od.writeAttr("arrived", myVehicleControl->getArrivedVehicleNo());
698 520101 : od.writeAttr("collisions", myVehicleControl->getCollisionCount());
699 520101 : od.writeAttr("teleports", myVehicleControl->getTeleportCount());
700 520101 : od.writeAttr("halting", myVehicleControl->getHaltingVehicleNo());
701 520101 : od.writeAttr("stopped", myVehicleControl->getStoppedVehiclesCount());
702 520101 : od.writeAttr("meanWaitingTime", meanWaitingTime);
703 520101 : od.writeAttr("meanTravelTime", meanTravelTime);
704 520101 : std::pair<double, double> meanSpeed = myVehicleControl->getVehicleMeanSpeeds();
705 520101 : od.writeAttr("meanSpeed", meanSpeed.first);
706 520101 : od.writeAttr("meanSpeedRelative", meanSpeed.second);
707 520101 : od.writeAttr("discarded", myVehicleControl->getDiscardedVehicleNo());
708 520101 : if (myLogExecutionTime) {
709 471634 : od.writeAttr("duration", mySimStepDuration);
710 : }
711 1040202 : od.closeTag();
712 : }
713 57121193 : if (hasPersonOutput) {
714 4752 : OutputDevice& od = OutputDevice::getDeviceByOption("person-summary-output");
715 4752 : MSTransportableControl& pc = getPersonControl();
716 4752 : od.openTag("step");
717 9504 : od.writeAttr("time", time2string(myStep));
718 4752 : od.writeAttr("loaded", pc.getLoadedNumber());
719 4752 : od.writeAttr("inserted", pc.getDepartedNumber());
720 9504 : od.writeAttr("walking", pc.getMovingNumber());
721 4752 : od.writeAttr("waitingForRide", pc.getWaitingForVehicleNumber());
722 9504 : od.writeAttr("riding", pc.getRidingNumber());
723 9504 : od.writeAttr("stopping", pc.getWaitingUntilNumber());
724 9504 : od.writeAttr("jammed", pc.getJammedNumber());
725 9504 : od.writeAttr("ended", pc.getEndedNumber());
726 9504 : od.writeAttr("arrived", pc.getArrivedNumber());
727 9504 : od.writeAttr("teleports", pc.getTeleportCount());
728 4752 : od.writeAttr("discarded", pc.getDiscardedNumber());
729 4752 : if (myLogExecutionTime) {
730 0 : od.writeAttr("duration", mySimStepDuration);
731 : }
732 9504 : od.closeTag();
733 : }
734 : }
735 :
736 :
737 : void
738 39232 : MSNet::closeSimulation(SUMOTime start, const std::string& reason) {
739 : // report the end when wished
740 78464 : WRITE_MESSAGE(TLF("Simulation ended at time: %.", time2string(getCurrentTimeStep())));
741 39232 : if (reason != "") {
742 77642 : WRITE_MESSAGE(TL("Reason: ") + reason);
743 : }
744 39232 : myDetectorControl->close(myStep);
745 40672 : if (MSStopOut::active() && OptionsCont::getOptions().getBool("stop-output.write-unfinished")) {
746 122 : MSStopOut::getInstance()->generateOutputForUnfinished();
747 : }
748 39232 : MSDevice_Vehroutes::writePendingOutput(OptionsCont::getOptions().getBool("vehroute-output.write-unfinished"));
749 78464 : if (OptionsCont::getOptions().getBool("tripinfo-output.write-unfinished")) {
750 953 : MSDevice_Tripinfo::generateOutputForUnfinished();
751 : }
752 78464 : if (OptionsCont::getOptions().isSet("chargingstations-output")) {
753 228 : if (!OptionsCont::getOptions().getBool("chargingstations-output.aggregated")) {
754 94 : writeChargingStationOutput();
755 40 : } else if (OptionsCont::getOptions().getBool("chargingstations-output.aggregated.write-unfinished")) {
756 12 : MSChargingStationExport::write(OutputDevice::getDeviceByOption("chargingstations-output"), true);
757 : }
758 : }
759 78464 : if (OptionsCont::getOptions().isSet("overheadwiresegments-output")) {
760 5 : writeOverheadWireSegmentOutput();
761 : }
762 78464 : if (OptionsCont::getOptions().isSet("substations-output")) {
763 5 : writeSubstationOutput();
764 : }
765 39232 : writeRailSignalBlocks();
766 39232 : const long now = SysUtils::getCurrentMillis();
767 66015 : if (myLogExecutionTime || OptionsCont::getOptions().getBool("duration-log.statistics")) {
768 25534 : WRITE_MESSAGE(generateStatistics(start, now));
769 : }
770 78464 : if (OptionsCont::getOptions().isSet("statistic-output")) {
771 376 : writeStatistics(start, now);
772 : }
773 : // maybe write a final line of output if reporting is periodic
774 39232 : writeSummaryOutput(true);
775 39232 : }
776 :
777 :
778 : void
779 57086395 : MSNet::simulationStep(const bool onlyMove) {
780 57086395 : if (myStepCompletionMissing) {
781 4 : postMoveStep();
782 4 : myStepCompletionMissing = false;
783 2562 : return;
784 : }
785 : #ifdef DEBUG_SIMSTEP
786 : std::cout << SIMTIME << ": MSNet::simulationStep() called"
787 : << ", myStep = " << myStep
788 : << std::endl;
789 : #endif
790 : TraCIServer* t = TraCIServer::getInstance();
791 : int lastTraCICmd = 0;
792 57086391 : if (t != nullptr) {
793 8852547 : if (myLogExecutionTime) {
794 8681209 : myTraCIStepDuration = SysUtils::getCurrentMillis();
795 : }
796 8852547 : lastTraCICmd = t->processCommands(myStep);
797 : #ifdef DEBUG_SIMSTEP
798 : bool loadRequested = !TraCI::getLoadArgs().empty();
799 : assert(t->getTargetTime() >= myStep || loadRequested || TraCIServer::wasClosed());
800 : #endif
801 8852524 : if (myLogExecutionTime) {
802 8681190 : myTraCIStepDuration = SysUtils::getCurrentMillis() - myTraCIStepDuration;
803 : }
804 8852524 : if (TraCIServer::wasClosed() || !t->getLoadArgs().empty()) {
805 : return;
806 : }
807 : }
808 : #ifdef DEBUG_SIMSTEP
809 : std::cout << SIMTIME << ": TraCI target time: " << t->getTargetTime() << std::endl;
810 : #endif
811 : // execute beginOfTimestepEvents
812 57083814 : if (myLogExecutionTime) {
813 24934735 : mySimStepDuration = SysUtils::getCurrentMillis();
814 : }
815 : // simulation state output
816 57083814 : std::vector<SUMOTime>::iterator timeIt = std::find(myStateDumpTimes.begin(), myStateDumpTimes.end(), myStep);
817 57083814 : if (timeIt != myStateDumpTimes.end()) {
818 315 : const int dist = (int)distance(myStateDumpTimes.begin(), timeIt);
819 315 : MSStateHandler::saveState(myStateDumpFiles[dist], myStep);
820 : }
821 57083814 : if (myStateDumpPeriod > 0 && myStep % myStateDumpPeriod == 0) {
822 84 : std::string timeStamp = time2string(myStep);
823 : std::replace(timeStamp.begin(), timeStamp.end(), ':', '-');
824 84 : const std::string filename = myStateDumpPrefix + "_" + timeStamp + myStateDumpSuffix;
825 84 : MSStateHandler::saveState(filename, myStep);
826 84 : myPeriodicStateFiles.push_back(filename);
827 84 : int keep = OptionsCont::getOptions().getInt("save-state.period.keep");
828 84 : if (keep > 0 && (int)myPeriodicStateFiles.size() > keep) {
829 0 : std::remove(myPeriodicStateFiles.front().c_str());
830 : myPeriodicStateFiles.erase(myPeriodicStateFiles.begin());
831 : }
832 : }
833 57083814 : myBeginOfTimestepEvents->execute(myStep);
834 57083808 : if (MSRailSignalControl::hasInstance()) {
835 8854466 : MSRailSignalControl::getInstance().updateSignals(myStep);
836 : }
837 : #ifdef HAVE_FOX
838 57083808 : MSRoutingEngine::waitForAll();
839 : #endif
840 57083808 : if (MSGlobals::gCheck4Accidents && !MSGlobals::gUseMesoSim) {
841 43951088 : myEdges->detectCollisions(myStep, STAGE_EVENTS);
842 : }
843 : // check whether the tls programs need to be switched
844 57083808 : myLogics->check2Switch(myStep);
845 :
846 57083808 : if (MSGlobals::gUseMesoSim) {
847 13132720 : MSGlobals::gMesoNet->simulate(myStep);
848 : } else {
849 : // assure all lanes with vehicles are 'active'
850 43951088 : myEdges->patchActiveLanes();
851 :
852 : // compute safe velocities for all vehicles for the next few lanes
853 : // also register ApproachingVehicleInformation for all links
854 43951088 : myEdges->planMovements(myStep);
855 :
856 : // register junction approaches based on planned velocities as basis for right-of-way decision
857 43951088 : myEdges->setJunctionApproaches();
858 :
859 : // decide right-of-way and execute movements
860 43951088 : myEdges->executeMovements(myStep);
861 43951085 : if (MSGlobals::gCheck4Accidents) {
862 43951085 : myEdges->detectCollisions(myStep, STAGE_MOVEMENTS);
863 : }
864 :
865 : // vehicles may change lanes
866 43951085 : myEdges->changeLanes(myStep);
867 :
868 43951085 : if (MSGlobals::gCheck4Accidents) {
869 43951085 : myEdges->detectCollisions(myStep, STAGE_LANECHANGE);
870 : }
871 : }
872 : // flush arrived meso vehicles and micro vehicles that were removed due to collision
873 57083805 : myVehicleControl->removePending();
874 57083805 : loadRoutes();
875 :
876 : // persons
877 57083789 : if (myPersonControl != nullptr && myPersonControl->hasTransportables()) {
878 3466467 : myPersonControl->checkWaiting(this, myStep);
879 : }
880 : // containers
881 57083739 : if (myContainerControl != nullptr && myContainerControl->hasTransportables()) {
882 5039867 : myContainerControl->checkWaiting(this, myStep);
883 : }
884 57083739 : if (MSRailSignalControl::hasInstance()) {
885 8854466 : MSRailSignalControl::getInstance().resetWaitRelations();
886 : // preserve waitRelation from insertion for the next step
887 : }
888 : // insert vehicles
889 57083739 : myInserter->determineCandidates(myStep);
890 57083694 : myInsertionEvents->execute(myStep);
891 : #ifdef HAVE_FOX
892 57083598 : MSRoutingEngine::waitForAll();
893 : #endif
894 57083574 : myInserter->emitVehicles(myStep);
895 57083422 : if (MSGlobals::gCheck4Accidents && !MSGlobals::gUseMesoSim) {
896 : //myEdges->patchActiveLanes(); // @note required to detect collisions on lanes that were empty before insertion. wasteful?
897 43950812 : myEdges->detectCollisions(myStep, STAGE_INSERTIONS);
898 : }
899 57083422 : MSVehicleTransfer::getInstance()->checkInsertions(myStep);
900 :
901 : // execute endOfTimestepEvents
902 57083422 : myEndOfTimestepEvents->execute(myStep);
903 :
904 57083413 : if (myLogExecutionTime) {
905 24934565 : myTraCIStepDuration -= SysUtils::getCurrentMillis();
906 : }
907 57083413 : if (onlyMove) {
908 4 : myStepCompletionMissing = true;
909 4 : return;
910 : }
911 57083409 : if (t != nullptr && lastTraCICmd == libsumo::CMD_EXECUTEMOVE) {
912 6 : t->processCommands(myStep, true);
913 : }
914 57083409 : postMoveStep();
915 : }
916 :
917 :
918 : void
919 57083413 : MSNet::postMoveStep() {
920 57083413 : const int numControlled = libsumo::Helper::postProcessRemoteControl();
921 57083413 : if (numControlled > 0 && MSGlobals::gCheck4Accidents) {
922 10332 : myEdges->detectCollisions(myStep, STAGE_REMOTECONTROL);
923 : }
924 57083413 : if (myLogExecutionTime) {
925 24934565 : myTraCIStepDuration += SysUtils::getCurrentMillis();
926 24934565 : myTraCIMillis += myTraCIStepDuration;
927 : }
928 57083413 : if (MSGlobals::gCheck4Accidents && !MSGlobals::gUseMesoSim) {
929 : // collisions from the previous step were kept to avoid duplicate
930 : // warnings. we must remove them now to ensure correct output.
931 43950807 : removeOutdatedCollisions();
932 : }
933 : // update and write (if needed) detector values
934 57083413 : mySimStepDuration = SysUtils::getCurrentMillis() - mySimStepDuration;
935 57083413 : writeOutput();
936 :
937 57083397 : if (myLogExecutionTime) {
938 24934565 : myVehiclesMoved += myVehicleControl->getRunningVehicleNo();
939 24934565 : if (myPersonControl != nullptr) {
940 2697783 : myPersonsMoved += myPersonControl->getRunningNumber();
941 : }
942 : }
943 57083397 : myStep += DELTA_T;
944 57083397 : }
945 :
946 :
947 : MSNet::SimulationState
948 56988463 : MSNet::simulationState(SUMOTime stopTime) const {
949 56988463 : if (TraCIServer::wasClosed()) {
950 : return SIMSTATE_CONNECTION_CLOSED;
951 : }
952 56985826 : if (TraCIServer::getInstance() != nullptr && !TraCIServer::getInstance()->getLoadArgs().empty()) {
953 : return SIMSTATE_LOADING;
954 : }
955 56985813 : if ((stopTime < 0 || myStep > stopTime) && TraCIServer::getInstance() == nullptr && (stopTime > 0 || myStep > myEdgeDataEndTime)) {
956 32120570 : if ((myVehicleControl->getActiveVehicleCount() == 0)
957 5605143 : && (myInserter->getPendingFlowCount() == 0)
958 1949962 : && (myPersonControl == nullptr || !myPersonControl->hasNonWaiting())
959 408530 : && (myContainerControl == nullptr || !myContainerControl->hasNonWaiting())
960 32181214 : && !MSDevice_Taxi::hasServableReservations()) {
961 : return SIMSTATE_NO_FURTHER_VEHICLES;
962 : }
963 : }
964 56940269 : if (stopTime >= 0 && myStep >= stopTime) {
965 : return SIMSTATE_END_STEP_REACHED;
966 : }
967 56922799 : if (myMaxTeleports >= 0 && myVehicleControl->getTeleportCount() > myMaxTeleports) {
968 : return SIMSTATE_TOO_MANY_TELEPORTS;
969 : }
970 56922791 : if (myAmInterrupted) {
971 12 : return SIMSTATE_INTERRUPTED;
972 : }
973 : return SIMSTATE_RUNNING;
974 : }
975 :
976 :
977 : MSNet::SimulationState
978 56980328 : MSNet::adaptToState(MSNet::SimulationState state, const bool isLibsumo) const {
979 56980328 : if (state == SIMSTATE_LOADING) {
980 13 : OptionsIO::setArgs(TraCIServer::getInstance()->getLoadArgs());
981 : TraCIServer::getInstance()->getLoadArgs().clear();
982 56980315 : } else if (state != SIMSTATE_RUNNING && ((TraCIServer::getInstance() != nullptr && !TraCIServer::wasClosed()) || isLibsumo)) {
983 : // overrides SIMSTATE_END_STEP_REACHED, e.g. (TraCI / Libsumo ignore SUMO's --end option)
984 20127 : return SIMSTATE_RUNNING;
985 56960188 : } else if (state == SIMSTATE_NO_FURTHER_VEHICLES) {
986 27510 : if (myPersonControl != nullptr) {
987 6755 : myPersonControl->abortAnyWaitingForVehicle();
988 : }
989 27510 : if (myContainerControl != nullptr) {
990 1863 : myContainerControl->abortAnyWaitingForVehicle();
991 : }
992 27510 : myVehicleControl->abortWaiting();
993 : }
994 : return state;
995 : }
996 :
997 :
998 : std::string
999 38634 : MSNet::getStateMessage(MSNet::SimulationState state) {
1000 38634 : switch (state) {
1001 : case MSNet::SIMSTATE_RUNNING:
1002 411 : return "";
1003 : case MSNet::SIMSTATE_END_STEP_REACHED:
1004 7755 : return TL("The final simulation step has been reached.");
1005 : case MSNet::SIMSTATE_NO_FURTHER_VEHICLES:
1006 27896 : return TL("All vehicles have left the simulation.");
1007 : case MSNet::SIMSTATE_CONNECTION_CLOSED:
1008 2541 : return TL("TraCI requested termination.");
1009 : case MSNet::SIMSTATE_ERROR_IN_SIM:
1010 0 : return TL("An error occurred (see log).");
1011 : case MSNet::SIMSTATE_INTERRUPTED:
1012 12 : return TL("Interrupted.");
1013 : case MSNet::SIMSTATE_TOO_MANY_TELEPORTS:
1014 6 : return TL("Too many teleports.");
1015 : case MSNet::SIMSTATE_LOADING:
1016 13 : return TL("TraCI issued load command.");
1017 : default:
1018 0 : return TL("Unknown reason.");
1019 : }
1020 : }
1021 :
1022 :
1023 : void
1024 40907 : MSNet::clearAll() {
1025 : // clear container
1026 40907 : MSEdge::clear();
1027 40907 : MSLane::clear();
1028 40907 : MSRoute::clear();
1029 40907 : delete MSVehicleTransfer::getInstance();
1030 40907 : MSDevice::cleanupAll();
1031 40907 : MSCalibrator::cleanup();
1032 82317 : while (!MSLaneSpeedTrigger::getInstances().empty()) {
1033 503 : delete MSLaneSpeedTrigger::getInstances().begin()->second;
1034 : }
1035 44907 : while (!MSTriggeredRerouter::getInstances().empty()) {
1036 4000 : delete MSTriggeredRerouter::getInstances().begin()->second;
1037 : }
1038 40907 : MSDevice_BTsender::cleanup();
1039 40907 : MSDevice_SSM::cleanup();
1040 40907 : MSDevice_ToC::cleanup();
1041 40907 : MSStopOut::cleanup();
1042 40907 : MSRailSignalConstraint::cleanup();
1043 40907 : MSRailSignalControl::cleanup();
1044 40907 : MSDriveWay::cleanup();
1045 : TraCIServer* t = TraCIServer::getInstance();
1046 40907 : if (t != nullptr) {
1047 2579 : t->cleanup();
1048 : }
1049 40907 : libsumo::Helper::cleanup();
1050 40907 : OutputDevice::closeAll(true);
1051 40907 : }
1052 :
1053 :
1054 : void
1055 186 : MSNet::clearState(const SUMOTime step, bool quickReload) {
1056 186 : MSGlobals::gClearState = true;
1057 186 : if (MSGlobals::gUseMesoSim) {
1058 2 : MSGlobals::gMesoNet->clearState();
1059 259 : for (MSEdge* const edge : MSEdge::getAllEdges()) {
1060 534 : for (MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*edge); s != nullptr; s = s->getNextSegment()) {
1061 277 : s->clearState();
1062 : }
1063 : }
1064 : } else {
1065 8341 : for (MSEdge* const edge : MSEdge::getAllEdges()) {
1066 18198 : for (MSLane* const lane : edge->getLanes()) {
1067 10041 : lane->getVehiclesSecure();
1068 10041 : lane->clearState();
1069 10041 : lane->releaseVehicles();
1070 : }
1071 8157 : edge->clearState();
1072 : }
1073 : }
1074 186 : myInserter->clearState();
1075 : // detectors may still reference persons/vehicles
1076 186 : myDetectorControl->updateDetectors(myStep);
1077 186 : myDetectorControl->writeOutput(myStep, true);
1078 186 : myDetectorControl->clearState(step);
1079 :
1080 186 : if (myPersonControl != nullptr) {
1081 25 : myPersonControl->clearState();
1082 : }
1083 186 : if (myContainerControl != nullptr) {
1084 0 : myContainerControl->clearState();
1085 : }
1086 : // delete vtypes after transportables have removed their types
1087 186 : myVehicleControl->clearState(true);
1088 186 : MSVehicleTransfer::getInstance()->clearState();
1089 186 : myLogics->clearState(step, quickReload);
1090 : // delete all routes after vehicles and detector output is done
1091 186 : MSRoute::dict_clearState();
1092 236 : for (auto& item : myStoppingPlaces) {
1093 100 : for (auto& item2 : item.second) {
1094 50 : item2.second->clearState();
1095 : }
1096 : }
1097 186 : myShapeContainer->clearState();
1098 186 : myBeginOfTimestepEvents->clearState(myStep, step);
1099 186 : myEndOfTimestepEvents->clearState(myStep, step);
1100 186 : myInsertionEvents->clearState(myStep, step);
1101 186 : MSRailSignalControl::clearState();
1102 186 : MSDriveWay::clearState();
1103 186 : myStep = step;
1104 186 : MSGlobals::gClearState = false;
1105 186 : }
1106 :
1107 :
1108 : void
1109 57083413 : MSNet::writeOutput() {
1110 : // update detector values
1111 57083413 : myDetectorControl->updateDetectors(myStep);
1112 57083404 : const OptionsCont& oc = OptionsCont::getOptions();
1113 :
1114 : // check state dumps
1115 114166808 : if (oc.isSet("netstate-dump")) {
1116 309460 : MSXMLRawOut::write(OutputDevice::getDeviceByOption("netstate-dump"), *myEdges, myStep,
1117 : oc.getInt("netstate-dump.precision"));
1118 : }
1119 :
1120 : // check fcd dumps
1121 114166808 : if (OptionsCont::getOptions().isSet("fcd-output")) {
1122 10294972 : if (OptionsCont::getOptions().isSet("person-fcd-output")) {
1123 24 : MSFCDExport::write(OutputDevice::getDeviceByOption("fcd-output"), myStep, SUMO_TAG_VEHICLE);
1124 48 : MSFCDExport::write(OutputDevice::getDeviceByOption("person-fcd-output"), myStep, SUMO_TAG_PERSON);
1125 : } else {
1126 10294924 : MSFCDExport::write(OutputDevice::getDeviceByOption("fcd-output"), myStep);
1127 : }
1128 : }
1129 :
1130 : // check emission dumps
1131 114166808 : if (OptionsCont::getOptions().isSet("emission-output")) {
1132 215216 : MSEmissionExport::write(OutputDevice::getDeviceByOption("emission-output"), myStep);
1133 : }
1134 :
1135 : // battery dumps
1136 114166808 : if (OptionsCont::getOptions().isSet("battery-output")) {
1137 139796 : MSBatteryExport::write(OutputDevice::getDeviceByOption("battery-output"), myStep,
1138 : oc.getInt("battery-output.precision"));
1139 : }
1140 :
1141 : // charging station aggregated dumps
1142 57170728 : if (OptionsCont::getOptions().isSet("chargingstations-output") && OptionsCont::getOptions().getBool("chargingstations-output.aggregated")) {
1143 22240 : MSChargingStationExport::write(OutputDevice::getDeviceByOption("chargingstations-output"));
1144 : }
1145 :
1146 : // elecHybrid dumps
1147 114166808 : if (OptionsCont::getOptions().isSet("elechybrid-output")) {
1148 450 : std::string output = OptionsCont::getOptions().getString("elechybrid-output");
1149 :
1150 900 : if (oc.getBool("elechybrid-output.aggregated")) {
1151 : // build a xml file with aggregated device.elechybrid output
1152 600 : MSElecHybridExport::writeAggregated(OutputDevice::getDeviceByOption("elechybrid-output"), myStep,
1153 : oc.getInt("elechybrid-output.precision"));
1154 : } else {
1155 : // build a separate xml file for each vehicle equipped with device.elechybrid
1156 : // RICE_TODO: Does this have to be placed here in MSNet.cpp ?
1157 150 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
1158 204 : for (MSVehicleControl::constVehIt it = vc.loadedVehBegin(); it != vc.loadedVehEnd(); ++it) {
1159 54 : const SUMOVehicle* veh = it->second;
1160 54 : if (!veh->isOnRoad()) {
1161 0 : continue;
1162 : }
1163 54 : if (static_cast<MSDevice_ElecHybrid*>(veh->getDevice(typeid(MSDevice_ElecHybrid))) != nullptr) {
1164 : std::string vehID = veh->getID();
1165 54 : std::string filename2 = output + "_" + vehID + ".xml";
1166 54 : OutputDevice& dev = OutputDevice::getDevice(filename2);
1167 : std::map<SumoXMLAttr, std::string> attrs;
1168 54 : attrs[SUMO_ATTR_VEHICLE] = vehID;
1169 54 : attrs[SUMO_ATTR_MAXIMUMBATTERYCAPACITY] = toString(dynamic_cast<MSDevice_ElecHybrid*>(veh->getDevice(typeid(MSDevice_ElecHybrid)))->getMaximumBatteryCapacity());
1170 54 : attrs[SUMO_ATTR_RECUPERATIONENABLE] = toString(MSGlobals::gOverheadWireRecuperation);
1171 108 : dev.writeXMLHeader("elecHybrid-export", "", attrs);
1172 108 : MSElecHybridExport::write(OutputDevice::getDevice(filename2), veh, myStep, oc.getInt("elechybrid-output.precision"));
1173 : }
1174 : }
1175 : }
1176 : }
1177 :
1178 :
1179 : // check full dumps
1180 114166808 : if (OptionsCont::getOptions().isSet("full-output")) {
1181 1138 : MSGlobals::gHaveEmissions = true;
1182 2276 : MSFullExport::write(OutputDevice::getDeviceByOption("full-output"), myStep);
1183 : }
1184 :
1185 : // check queue dumps
1186 114166808 : if (OptionsCont::getOptions().isSet("queue-output")) {
1187 324414 : MSQueueExport::write(OutputDevice::getDeviceByOption("queue-output"), myStep);
1188 : }
1189 :
1190 : // check amitran dumps
1191 114166808 : if (OptionsCont::getOptions().isSet("amitran-output")) {
1192 2340 : MSAmitranTrajectories::write(OutputDevice::getDeviceByOption("amitran-output"), myStep);
1193 : }
1194 :
1195 : // check vtk dumps
1196 114166808 : if (OptionsCont::getOptions().isSet("vtk-output")) {
1197 :
1198 60 : if (MSNet::getInstance()->getVehicleControl().getRunningVehicleNo() > 0) {
1199 60 : std::string timestep = time2string(myStep);
1200 60 : if (TS >= 1.0) {
1201 48 : timestep = timestep.substr(0, timestep.length() - 3);
1202 36 : } else if (DELTA_T % 100 == 0) {
1203 72 : timestep = timestep.substr(0, timestep.length() - 1);
1204 : }
1205 66 : std::string output = OptionsCont::getOptions().getString("vtk-output");
1206 66 : std::string filename = output + "_" + timestep + ".vtp";
1207 :
1208 60 : OutputDevice_File dev(filename);
1209 :
1210 : //build a huge mass of xml files
1211 54 : MSVTKExport::write(dev, myStep);
1212 :
1213 54 : }
1214 :
1215 : }
1216 :
1217 57083398 : writeSummaryOutput();
1218 :
1219 : // write detector values
1220 57083398 : myDetectorControl->writeOutput(myStep + DELTA_T, false);
1221 :
1222 : // write link states
1223 114166794 : if (OptionsCont::getOptions().isSet("link-output")) {
1224 3704 : OutputDevice& od = OutputDevice::getDeviceByOption("link-output");
1225 3704 : od.openTag("timestep");
1226 3704 : od.writeAttr(SUMO_ATTR_ID, STEPS2TIME(myStep));
1227 70088 : for (const MSEdge* const edge : myEdges->getEdges()) {
1228 143648 : for (const MSLane* const lane : edge->getLanes()) {
1229 158588 : for (const MSLink* const link : lane->getLinkCont()) {
1230 162648 : link->writeApproaching(od, lane->getID());
1231 : }
1232 : }
1233 : }
1234 7408 : od.closeTag();
1235 : }
1236 :
1237 : // write SSM output
1238 59616650 : for (MSDevice_SSM* dev : MSDevice_SSM::getInstances()) {
1239 2533253 : dev->updateAndWriteOutput();
1240 : }
1241 :
1242 : // write ToC output
1243 57099116 : for (MSDevice_ToC* dev : MSDevice_ToC::getInstances()) {
1244 15719 : if (dev->generatesOutput()) {
1245 15513 : dev->writeOutput();
1246 : }
1247 : }
1248 :
1249 114166794 : if (OptionsCont::getOptions().isSet("collision-output")) {
1250 10356 : writeCollisions();
1251 : }
1252 57083397 : }
1253 :
1254 :
1255 : bool
1256 0 : MSNet::logSimulationDuration() const {
1257 0 : return myLogExecutionTime;
1258 : }
1259 :
1260 :
1261 : MSTransportableControl&
1262 12822206 : MSNet::getPersonControl() {
1263 12822206 : if (myPersonControl == nullptr) {
1264 6548 : myPersonControl = new MSTransportableControl(true);
1265 : }
1266 12822182 : return *myPersonControl;
1267 : }
1268 :
1269 :
1270 : MSTransportableControl&
1271 9257001 : MSNet::getContainerControl() {
1272 9257001 : if (myContainerControl == nullptr) {
1273 1782 : myContainerControl = new MSTransportableControl(false);
1274 : }
1275 9257001 : return *myContainerControl;
1276 : }
1277 :
1278 : MSDynamicShapeUpdater*
1279 25 : MSNet::makeDynamicShapeUpdater() {
1280 25 : myDynamicShapeUpdater = std::unique_ptr<MSDynamicShapeUpdater> (new MSDynamicShapeUpdater(*myShapeContainer));
1281 25 : return myDynamicShapeUpdater.get();
1282 : }
1283 :
1284 : MSEdgeWeightsStorage&
1285 6630080 : MSNet::getWeightsStorage() {
1286 6630080 : if (myEdgeWeights == nullptr) {
1287 1824 : myEdgeWeights = new MSEdgeWeightsStorage();
1288 : }
1289 6630080 : return *myEdgeWeights;
1290 : }
1291 :
1292 :
1293 : void
1294 129 : MSNet::preSimStepOutput() const {
1295 129 : std::cout << "Step #" << time2string(myStep);
1296 129 : }
1297 :
1298 :
1299 : void
1300 129 : MSNet::postSimStepOutput() const {
1301 129 : if (myLogExecutionTime) {
1302 127 : std::ostringstream oss;
1303 : oss.setf(std::ios::fixed, std::ios::floatfield); // use decimal format
1304 : oss.setf(std::ios::showpoint); // print decimal point
1305 127 : oss << std::setprecision(gPrecision);
1306 127 : if (mySimStepDuration != 0) {
1307 73 : const double durationSec = (double)mySimStepDuration / 1000.;
1308 73 : oss << " (" << mySimStepDuration << "ms ~= "
1309 73 : << (TS / durationSec) << "*RT, ~"
1310 73 : << ((double) myVehicleControl->getRunningVehicleNo() / durationSec);
1311 : } else {
1312 54 : oss << " (0ms ?*RT. ?";
1313 : }
1314 127 : oss << "UPS, ";
1315 127 : if (TraCIServer::getInstance() != nullptr) {
1316 79 : oss << "TraCI: " << myTraCIStepDuration << "ms, ";
1317 : }
1318 127 : oss << "vehicles TOT " << myVehicleControl->getDepartedVehicleNo()
1319 254 : << " ACT " << myVehicleControl->getRunningVehicleNo()
1320 127 : << " BUF " << myInserter->getWaitingVehicleNo()
1321 127 : << ") ";
1322 254 : std::string prev = "Step #" + time2string(myStep - DELTA_T);
1323 254 : std::cout << oss.str().substr(0, 90 - prev.length());
1324 127 : }
1325 129 : std::cout << '\r';
1326 129 : }
1327 :
1328 :
1329 : void
1330 10960 : MSNet::addVehicleStateListener(VehicleStateListener* listener) {
1331 10960 : if (find(myVehicleStateListeners.begin(), myVehicleStateListeners.end(), listener) == myVehicleStateListeners.end()) {
1332 10960 : myVehicleStateListeners.push_back(listener);
1333 : }
1334 10960 : }
1335 :
1336 :
1337 : void
1338 59 : MSNet::removeVehicleStateListener(VehicleStateListener* listener) {
1339 59 : std::vector<VehicleStateListener*>::iterator i = std::find(myVehicleStateListeners.begin(), myVehicleStateListeners.end(), listener);
1340 59 : if (i != myVehicleStateListeners.end()) {
1341 59 : myVehicleStateListeners.erase(i);
1342 : }
1343 59 : }
1344 :
1345 :
1346 : void
1347 16478322 : MSNet::informVehicleStateListener(const SUMOVehicle* const vehicle, VehicleState to, const std::string& info) {
1348 : #ifdef HAVE_FOX
1349 16478322 : ScopedLocker<> lock(myVehicleStateListenerMutex, MSGlobals::gNumThreads > 1);
1350 : #endif
1351 17157526 : for (VehicleStateListener* const listener : myVehicleStateListeners) {
1352 679204 : listener->vehicleStateChanged(vehicle, to, info);
1353 : }
1354 16478322 : }
1355 :
1356 :
1357 : void
1358 3715 : MSNet::addTransportableStateListener(TransportableStateListener* listener) {
1359 3715 : if (find(myTransportableStateListeners.begin(), myTransportableStateListeners.end(), listener) == myTransportableStateListeners.end()) {
1360 3715 : myTransportableStateListeners.push_back(listener);
1361 : }
1362 3715 : }
1363 :
1364 :
1365 : void
1366 0 : MSNet::removeTransportableStateListener(TransportableStateListener* listener) {
1367 0 : std::vector<TransportableStateListener*>::iterator i = std::find(myTransportableStateListeners.begin(), myTransportableStateListeners.end(), listener);
1368 0 : if (i != myTransportableStateListeners.end()) {
1369 0 : myTransportableStateListeners.erase(i);
1370 : }
1371 0 : }
1372 :
1373 :
1374 : void
1375 963078 : MSNet::informTransportableStateListener(const MSTransportable* const transportable, TransportableState to, const std::string& info) {
1376 : #ifdef HAVE_FOX
1377 963078 : ScopedLocker<> lock(myTransportableStateListenerMutex, MSGlobals::gNumThreads > 1);
1378 : #endif
1379 965714 : for (TransportableStateListener* const listener : myTransportableStateListeners) {
1380 2636 : listener->transportableStateChanged(transportable, to, info);
1381 : }
1382 963078 : }
1383 :
1384 :
1385 : bool
1386 10920 : MSNet::registerCollision(const SUMOTrafficObject* collider, const SUMOTrafficObject* victim, const std::string& collisionType, const MSLane* lane, double pos) {
1387 : auto it = myCollisions.find(collider->getID());
1388 10920 : if (it != myCollisions.end()) {
1389 5212 : for (Collision& old : it->second) {
1390 5104 : if (old.victim == victim->getID()) {
1391 : // collision from previous step continues
1392 4323 : old.continuationTime = myStep;
1393 : return false;
1394 : }
1395 : }
1396 : } else {
1397 : // maybe the roles have been reversed
1398 : auto it2 = myCollisions.find(victim->getID());
1399 6489 : if (it2 != myCollisions.end()) {
1400 526 : for (Collision& old : it2->second) {
1401 364 : if (old.victim == collider->getID()) {
1402 : // collision from previous step continues (keep the old roles)
1403 199 : old.continuationTime = myStep;
1404 : return false;
1405 : }
1406 : }
1407 : }
1408 : }
1409 : Collision c;
1410 : c.victim = victim->getID();
1411 6398 : c.colliderType = collider->getVehicleType().getID();
1412 6398 : c.victimType = victim->getVehicleType().getID();
1413 6398 : c.colliderSpeed = collider->getSpeed();
1414 6398 : c.victimSpeed = victim->getSpeed();
1415 6398 : c.colliderFront = collider->getPosition();
1416 6398 : c.victimFront = victim->getPosition();
1417 6398 : c.colliderBack = collider->getPosition(-collider->getVehicleType().getLength());
1418 6398 : c.victimBack = victim->getPosition(-victim->getVehicleType().getLength());
1419 : c.type = collisionType;
1420 6398 : c.lane = lane;
1421 6398 : c.pos = pos;
1422 6398 : c.time = myStep;
1423 6398 : c.continuationTime = myStep;
1424 6398 : myCollisions[collider->getID()].push_back(c);
1425 : return true;
1426 6398 : }
1427 :
1428 :
1429 : void
1430 43950807 : MSNet::removeOutdatedCollisions() {
1431 43965626 : for (auto it = myCollisions.begin(); it != myCollisions.end();) {
1432 29858 : for (auto it2 = it->second.begin(); it2 != it->second.end();) {
1433 15039 : if (it2->continuationTime != myStep) {
1434 6386 : it2 = it->second.erase(it2);
1435 : } else {
1436 : it2++;
1437 : }
1438 : }
1439 14819 : if (it->second.size() == 0) {
1440 : it = myCollisions.erase(it);
1441 : } else {
1442 : it++;
1443 : }
1444 : }
1445 43950807 : }
1446 :
1447 :
1448 : bool
1449 83594 : MSNet::addStoppingPlace(SumoXMLTag category, MSStoppingPlace* stop) {
1450 83594 : if (category == SUMO_TAG_TRAIN_STOP) {
1451 13964 : category = SUMO_TAG_BUS_STOP;
1452 : }
1453 83594 : const bool isNew = myStoppingPlaces[category].add(stop->getID(), stop);
1454 83594 : if (isNew && stop->getMyName() != "") {
1455 15959 : myNamedStoppingPlaces[category][stop->getMyName()].push_back(stop);
1456 : }
1457 83594 : return isNew;
1458 : }
1459 :
1460 :
1461 : bool
1462 17 : MSNet::addTractionSubstation(MSTractionSubstation* substation) {
1463 17 : if (find(myTractionSubstations.begin(), myTractionSubstations.end(), substation) == myTractionSubstations.end()) {
1464 17 : myTractionSubstations.push_back(substation);
1465 17 : return true;
1466 : }
1467 : return false;
1468 : }
1469 :
1470 :
1471 : MSStoppingPlace*
1472 1772311 : MSNet::getStoppingPlace(const std::string& id, const SumoXMLTag category) const {
1473 : if (myStoppingPlaces.count(category) > 0) {
1474 : return myStoppingPlaces.find(category)->second.get(id);
1475 : }
1476 : return nullptr;
1477 : }
1478 :
1479 :
1480 : MSStoppingPlace*
1481 212189 : MSNet::getStoppingPlace(const std::string& id) const {
1482 1093577 : for (SumoXMLTag category : std::vector<SumoXMLTag>({SUMO_TAG_BUS_STOP, SUMO_TAG_PARKING_AREA, SUMO_TAG_CONTAINER_STOP, SUMO_TAG_CHARGING_STATION, SUMO_TAG_OVERHEAD_WIRE_SEGMENT})) {
1483 917810 : MSStoppingPlace* result = getStoppingPlace(id, category);
1484 917810 : if (result != nullptr) {
1485 : return result;
1486 : }
1487 212189 : }
1488 175767 : return nullptr;
1489 : }
1490 :
1491 :
1492 : std::string
1493 458897 : MSNet::getStoppingPlaceID(const MSLane* lane, const double pos, const SumoXMLTag category) const {
1494 : if (myStoppingPlaces.count(category) > 0) {
1495 924170 : for (const auto& it : myStoppingPlaces.find(category)->second) {
1496 849126 : MSStoppingPlace* stop = it.second;
1497 849126 : if (&stop->getLane() == lane && stop->getBeginLanePosition() - POSITION_EPS <= pos && stop->getEndLanePosition() + POSITION_EPS >= pos) {
1498 : return stop->getID();
1499 : }
1500 : }
1501 : }
1502 354369 : return "";
1503 : }
1504 :
1505 :
1506 : const std::vector<MSStoppingPlace*>&
1507 1583 : MSNet::getStoppingPlaceAlternatives(const std::string& name, SumoXMLTag category) const {
1508 1583 : if (category == SUMO_TAG_TRAIN_STOP) {
1509 : category = SUMO_TAG_BUS_STOP;
1510 : }
1511 : auto it = myNamedStoppingPlaces.find(category);
1512 1583 : if (it != myNamedStoppingPlaces.end()) {
1513 : auto it2 = it->second.find(name);
1514 1515 : if (it2 != it->second.end()) {
1515 1515 : return it2->second;
1516 : }
1517 : }
1518 : return myEmptyStoppingPlaceVector;
1519 : }
1520 :
1521 :
1522 : const NamedObjectCont<MSStoppingPlace*>&
1523 14221 : MSNet::getStoppingPlaces(SumoXMLTag category) const {
1524 : auto it = myStoppingPlaces.find(category);
1525 14221 : if (it != myStoppingPlaces.end()) {
1526 13912 : return it->second;
1527 : } else {
1528 : return myEmptyStoppingPlaceCont;
1529 : }
1530 : }
1531 :
1532 :
1533 : void
1534 94 : MSNet::writeChargingStationOutput() const {
1535 : if (myStoppingPlaces.count(SUMO_TAG_CHARGING_STATION) > 0) {
1536 180 : OutputDevice& output = OutputDevice::getDeviceByOption("chargingstations-output");
1537 538 : for (const auto& it : myStoppingPlaces.find(SUMO_TAG_CHARGING_STATION)->second) {
1538 448 : static_cast<MSChargingStation*>(it.second)->writeChargingStationOutput(output);
1539 : }
1540 : }
1541 94 : }
1542 :
1543 :
1544 : void
1545 39232 : MSNet::writeRailSignalBlocks() const {
1546 78464 : if (OptionsCont::getOptions().isSet("railsignal-block-output")) {
1547 1280 : OutputDevice& output = OutputDevice::getDeviceByOption("railsignal-block-output");
1548 4986 : for (auto tls : myLogics->getAllLogics()) {
1549 3706 : MSRailSignal* rs = dynamic_cast<MSRailSignal*>(tls);
1550 3706 : if (rs != nullptr) {
1551 3662 : rs->writeBlocks(output, false);
1552 : }
1553 1280 : }
1554 1280 : MSDriveWay::writeDepatureBlocks(output, false);
1555 : }
1556 78464 : if (OptionsCont::getOptions().isSet("railsignal-vehicle-output")) {
1557 132 : OutputDevice& output = OutputDevice::getDeviceByOption("railsignal-vehicle-output");
1558 460 : for (auto tls : myLogics->getAllLogics()) {
1559 328 : MSRailSignal* rs = dynamic_cast<MSRailSignal*>(tls);
1560 328 : if (rs != nullptr) {
1561 328 : rs->writeBlocks(output, true);
1562 : }
1563 132 : }
1564 132 : MSDriveWay::writeDepatureBlocks(output, true);
1565 : }
1566 39232 : }
1567 :
1568 :
1569 : void
1570 5 : MSNet::writeOverheadWireSegmentOutput() const {
1571 : if (myStoppingPlaces.count(SUMO_TAG_OVERHEAD_WIRE_SEGMENT) > 0) {
1572 10 : OutputDevice& output = OutputDevice::getDeviceByOption("overheadwiresegments-output");
1573 53 : for (const auto& it : myStoppingPlaces.find(SUMO_TAG_OVERHEAD_WIRE_SEGMENT)->second) {
1574 48 : static_cast<MSOverheadWire*>(it.second)->writeOverheadWireSegmentOutput(output);
1575 : }
1576 : }
1577 5 : }
1578 :
1579 :
1580 : void
1581 5 : MSNet::writeSubstationOutput() const {
1582 5 : if (myTractionSubstations.size() > 0) {
1583 5 : OutputDevice& output = OutputDevice::getDeviceByOption("substations-output");
1584 10 : output.setPrecision(OptionsCont::getOptions().getInt("substations-output.precision"));
1585 13 : for (auto& it : myTractionSubstations) {
1586 8 : it->writeTractionSubstationOutput(output);
1587 : }
1588 : }
1589 5 : }
1590 :
1591 :
1592 : MSTractionSubstation*
1593 19 : MSNet::findTractionSubstation(const std::string& substationId) {
1594 22 : for (std::vector<MSTractionSubstation*>::iterator it = myTractionSubstations.begin(); it != myTractionSubstations.end(); ++it) {
1595 22 : if ((*it)->getID() == substationId) {
1596 : return *it;
1597 : }
1598 : }
1599 : return nullptr;
1600 : }
1601 :
1602 :
1603 : bool
1604 0 : MSNet::existTractionSubstation(const std::string& substationId) {
1605 0 : for (std::vector<MSTractionSubstation*>::iterator it = myTractionSubstations.begin(); it != myTractionSubstations.end(); ++it) {
1606 0 : if ((*it)->getID() == substationId) {
1607 : return true;
1608 : }
1609 : }
1610 : return false;
1611 : }
1612 :
1613 :
1614 : MSVehicleRouter&
1615 122499 : MSNet::getRouterTT(int rngIndex, const Prohibitions& prohibited) const {
1616 122499 : if (MSGlobals::gNumSimThreads == 1) {
1617 104048 : rngIndex = 0;
1618 : }
1619 : if (myRouterTT.count(rngIndex) == 0) {
1620 1351 : const std::string routingAlgorithm = OptionsCont::getOptions().getString("routing-algorithm");
1621 1351 : if (routingAlgorithm == "dijkstra") {
1622 1265 : myRouterTT[rngIndex] = new DijkstraRouter<MSEdge, SUMOVehicle>(MSEdge::getAllEdges(), true, &MSNet::getTravelTime, nullptr, false, nullptr, true);
1623 : } else {
1624 86 : if (routingAlgorithm != "astar") {
1625 0 : WRITE_WARNINGF(TL("TraCI and Triggers cannot use routing algorithm '%'. using 'astar' instead."), routingAlgorithm);
1626 : }
1627 86 : myRouterTT[rngIndex] = new AStarRouter<MSEdge, SUMOVehicle, MSMapMatcher>(MSEdge::getAllEdges(), true, &MSNet::getTravelTime, nullptr, true);
1628 : }
1629 : }
1630 122499 : myRouterTT[rngIndex]->prohibit(prohibited);
1631 122499 : return *myRouterTT[rngIndex];
1632 : }
1633 :
1634 :
1635 : MSVehicleRouter&
1636 11 : MSNet::getRouterEffort(int rngIndex, const Prohibitions& prohibited) const {
1637 11 : if (MSGlobals::gNumSimThreads == 1) {
1638 11 : rngIndex = 0;
1639 : }
1640 : if (myRouterEffort.count(rngIndex) == 0) {
1641 11 : myRouterEffort[rngIndex] = new DijkstraRouter<MSEdge, SUMOVehicle>(MSEdge::getAllEdges(), true, &MSNet::getEffort, &MSNet::getTravelTime, false, nullptr, true);
1642 : }
1643 11 : myRouterEffort[rngIndex]->prohibit(prohibited);
1644 11 : return *myRouterEffort[rngIndex];
1645 : }
1646 :
1647 :
1648 : MSPedestrianRouter&
1649 852918 : MSNet::getPedestrianRouter(int rngIndex, const Prohibitions& prohibited) const {
1650 852918 : if (MSGlobals::gNumSimThreads == 1) {
1651 764147 : rngIndex = 0;
1652 : }
1653 : if (myPedestrianRouter.count(rngIndex) == 0) {
1654 2822 : myPedestrianRouter[rngIndex] = new MSPedestrianRouter();
1655 : }
1656 852918 : myPedestrianRouter[rngIndex]->prohibit(prohibited);
1657 852918 : return *myPedestrianRouter[rngIndex];
1658 : }
1659 :
1660 :
1661 : MSTransportableRouter&
1662 208687 : MSNet::getIntermodalRouter(int rngIndex, const int routingMode, const Prohibitions& prohibited) const {
1663 208687 : if (MSGlobals::gNumSimThreads == 1) {
1664 : rngIndex = 0;
1665 : }
1666 208687 : const OptionsCont& oc = OptionsCont::getOptions();
1667 208687 : const int key = rngIndex * oc.getInt("thread-rngs") + routingMode;
1668 : if (myIntermodalRouter.count(key) == 0) {
1669 4088 : const int carWalk = SUMOVehicleParserHelper::parseCarWalkTransfer(oc, MSDevice_Taxi::hasFleet() || myInserter->hasTaxiFlow());
1670 3920 : const std::string routingAlgorithm = OptionsCont::getOptions().getString("routing-algorithm");
1671 3920 : const double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
1672 3920 : if (routingMode == libsumo::ROUTING_MODE_COMBINED) {
1673 0 : myIntermodalRouter[key] = new MSTransportableRouter(MSNet::adaptIntermodalRouter, carWalk, taxiWait, routingAlgorithm, routingMode, new FareModul());
1674 : } else {
1675 3920 : myIntermodalRouter[key] = new MSTransportableRouter(MSNet::adaptIntermodalRouter, carWalk, taxiWait, routingAlgorithm, routingMode);
1676 : }
1677 : }
1678 208687 : myIntermodalRouter[key]->prohibit(prohibited);
1679 208687 : return *myIntermodalRouter[key];
1680 : }
1681 :
1682 :
1683 : void
1684 4857 : MSNet::adaptIntermodalRouter(MSTransportableRouter& router) {
1685 9714 : double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
1686 : // add access to all parking areas
1687 : EffortCalculator* const external = router.getExternalEffort();
1688 14569 : for (const auto& stopType : myInstance->myStoppingPlaces) {
1689 : // add access to all stopping places
1690 9712 : const SumoXMLTag element = stopType.first;
1691 35857 : for (const auto& i : stopType.second) {
1692 26145 : const MSEdge* const edge = &i.second->getLane().getEdge();
1693 26145 : router.getNetwork()->addAccess(i.first, edge, i.second->getBeginLanePosition(), i.second->getEndLanePosition(),
1694 : 0., element, false, taxiWait);
1695 26145 : if (element == SUMO_TAG_BUS_STOP) {
1696 : // add access to all public transport stops
1697 12639 : for (const auto& a : i.second->getAllAccessPos()) {
1698 1158 : router.getNetwork()->addAccess(i.first, &a.lane->getEdge(), a.startPos, a.endPos, a.length, element, true, taxiWait);
1699 : }
1700 11481 : if (external != nullptr) {
1701 0 : external->addStop(router.getNetwork()->getStopEdge(i.first)->getNumericalID(), *i.second);
1702 : }
1703 : }
1704 : }
1705 : }
1706 4857 : myInstance->getInsertionControl().adaptIntermodalRouter(router);
1707 4857 : myInstance->getVehicleControl().adaptIntermodalRouter(router);
1708 : // add access to transfer from walking to taxi-use
1709 4857 : if ((router.getCarWalkTransfer() & ModeChangeOptions::TAXI_PICKUP_ANYWHERE) != 0) {
1710 59650 : for (MSEdge* edge : myInstance->getEdgeControl().getEdges()) {
1711 59419 : if ((edge->getPermissions() & SVC_PEDESTRIAN) != 0 && (edge->getPermissions() & SVC_TAXI) != 0) {
1712 21639 : router.getNetwork()->addCarAccess(edge, SVC_TAXI, taxiWait);
1713 : }
1714 : }
1715 : }
1716 4857 : }
1717 :
1718 :
1719 : bool
1720 40768 : MSNet::checkElevation() {
1721 40768 : const MSEdgeVector& edges = myEdges->getEdges();
1722 1741315 : for (MSEdgeVector::const_iterator e = edges.begin(); e != edges.end(); ++e) {
1723 3749206 : for (std::vector<MSLane*>::const_iterator i = (*e)->getLanes().begin(); i != (*e)->getLanes().end(); ++i) {
1724 2048659 : if ((*i)->getShape().hasElevation()) {
1725 : return true;
1726 : }
1727 : }
1728 : }
1729 : return false;
1730 : }
1731 :
1732 :
1733 : bool
1734 40768 : MSNet::checkWalkingarea() {
1735 1264961 : for (const MSEdge* e : myEdges->getEdges()) {
1736 1234134 : if (e->getFunction() == SumoXMLEdgeFunc::WALKINGAREA) {
1737 : return true;
1738 : }
1739 : }
1740 : return false;
1741 : }
1742 :
1743 :
1744 : bool
1745 40768 : MSNet::checkBidiEdges() {
1746 1683864 : for (const MSEdge* e : myEdges->getEdges()) {
1747 1644138 : if (e->getBidiEdge() != nullptr) {
1748 : return true;
1749 : }
1750 : }
1751 : return false;
1752 : }
1753 :
1754 : bool
1755 279 : MSNet::warnOnce(const std::string& typeAndID) {
1756 279 : if (myWarnedOnce.find(typeAndID) == myWarnedOnce.end()) {
1757 279 : myWarnedOnce[typeAndID] = true;
1758 279 : return true;
1759 : }
1760 : return false;
1761 : }
1762 :
1763 :
1764 : MSMapMatcher*
1765 35 : MSNet::getMapMatcher() const {
1766 35 : auto loader = myRouteLoaders->getFirstLoader();
1767 35 : if (loader != nullptr) {
1768 35 : return dynamic_cast<MSMapMatcher*>(loader->getRouteHandler());
1769 : } else {
1770 : return nullptr;
1771 : }
1772 : }
1773 :
1774 : void
1775 0 : MSNet::quickReload() {
1776 0 : const OptionsCont& oc = OptionsCont::getOptions();
1777 0 : clearState(string2time(oc.getString("begin")), true);
1778 0 : NLBuilder::initRandomness();
1779 : // load traffic from additional files
1780 0 : for (std::string file : oc.getStringVector("additional-files")) {
1781 : // ignore failure on parsing calibrator flow
1782 0 : MSRouteHandler rh(file, true);
1783 0 : const long before = PROGRESS_BEGIN_TIME_MESSAGE("Loading traffic from '" + file + "'");
1784 0 : if (!XMLSubSys::runParser(rh, file, false)) {
1785 0 : throw ProcessError(TLF("Loading of % failed.", file));
1786 : }
1787 0 : PROGRESS_TIME_MESSAGE(before);
1788 0 : }
1789 0 : delete myRouteLoaders;
1790 0 : myRouteLoaders = NLBuilder::buildRouteLoaderControl(OptionsCont::getOptions());
1791 0 : updateGUI();
1792 0 : }
1793 :
1794 :
1795 : SUMOTime
1796 196 : MSNet::loadState(const std::string& fileName, const bool catchExceptions) {
1797 : // load time only
1798 196 : const SUMOTime newTime = MSStateHandler::MSStateTimeHandler::getTime(fileName);
1799 : // clean up state
1800 186 : clearState(newTime);
1801 : // load state
1802 186 : MSStateHandler h(fileName, 0);
1803 186 : XMLSubSys::runParser(h, fileName, false, false, false, catchExceptions);
1804 186 : if (MsgHandler::getErrorInstance()->wasInformed()) {
1805 0 : throw ProcessError(TLF("Loading state from '%' failed.", fileName));
1806 : }
1807 : // reset route loaders
1808 186 : delete myRouteLoaders;
1809 186 : myRouteLoaders = NLBuilder::buildRouteLoaderControl(OptionsCont::getOptions());
1810 : // prevent loading errors on rewound route file
1811 186 : MSGlobals::gStateLoaded = true;
1812 :
1813 186 : updateGUI();
1814 186 : return newTime;
1815 186 : }
1816 :
1817 :
1818 : /****************************************************************************/
|