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 7051554 : MSNet::getTravelTime(const MSEdge* const e, const SUMOVehicle* const v, double t) {
168 : double value;
169 7051554 : const MSVehicle* const veh = dynamic_cast<const MSVehicle* const>(v);
170 7050631 : if (veh != nullptr && veh->getWeightsStorage().retrieveExistingTravelTime(e, t, value)) {
171 522 : return value;
172 : }
173 7051032 : if (getInstance()->getWeightsStorage().retrieveExistingTravelTime(e, t, value)) {
174 177 : return value;
175 : }
176 7050855 : if (veh != nullptr) {
177 6864725 : if ((veh->getRoutingMode() & libsumo::ROUTING_MODE_AGGREGATED_CUSTOM) != 0) {
178 3471 : return MSRoutingEngine::getEffortExtra(e, v, t);
179 6861254 : } else if ((veh->getRoutingMode() & libsumo::ROUTING_MODE_AGGREGATED) != 0) {
180 567 : if (MSRoutingEngine::hasBikeSpeeds() && v->getVClass() == SVC_BICYCLE) {
181 0 : return MSRoutingEngine::getEffortBike(e, v, t);
182 : } else {
183 567 : return MSRoutingEngine::getEffort(e, v, t);
184 : }
185 6860687 : } else if (MSRoutingEngine::haveExtras()) {
186 6860687 : double tt = e->getMinimumTravelTime(v);
187 6860687 : MSRoutingEngine::applyExtras(e, v, SIMSTEP, tt);
188 6860687 : return tt;
189 : }
190 : }
191 186130 : return e->getMinimumTravelTime(v);
192 : }
193 :
194 :
195 : // ---------------------------------------------------------------------------
196 : // MSNet - methods
197 : // ---------------------------------------------------------------------------
198 : MSNet*
199 6161761732 : MSNet::getInstance(void) {
200 6161761732 : if (myInstance != nullptr) {
201 6161761687 : return myInstance;
202 : }
203 90 : throw ProcessError(TL("A network was not yet constructed."));
204 : }
205 :
206 : void
207 42946 : MSNet::initStatic() {
208 42946 : gRoutingPreferences = false;
209 42946 : MSDriveWay::init();
210 42946 : }
211 :
212 : void
213 42328 : MSNet::cleanupStatic() {
214 42328 : if (!MSGlobals::gUseMesoSim) {
215 35390 : MSVehicle::Influencer::cleanup();
216 : }
217 42328 : }
218 :
219 :
220 42946 : MSNet::MSNet(MSVehicleControl* vc, MSEventControl* beginOfTimestepEvents,
221 : MSEventControl* endOfTimestepEvents,
222 : MSEventControl* insertionEvents,
223 42946 : ShapeContainer* shapeCont):
224 42946 : myAmInterrupted(false),
225 42946 : myVehiclesMoved(0),
226 42946 : myPersonsMoved(0),
227 42946 : myHavePermissions(false),
228 42946 : myHasInternalLinks(false),
229 42946 : myJunctionHigherSpeeds(false),
230 42946 : myHasElevation(false),
231 42946 : myHasPedestrianNetwork(false),
232 42946 : myHasBidiEdges(false),
233 42946 : myEdgeDataEndTime(-1),
234 42946 : myDynamicShapeUpdater(nullptr) {
235 42946 : if (myInstance != nullptr) {
236 0 : throw ProcessError(TL("A network was already constructed."));
237 : }
238 42946 : OptionsCont& oc = OptionsCont::getOptions();
239 42946 : myStep = string2time(oc.getString("begin"));
240 42946 : myStateLoaderTime = myStep - 1,
241 42946 : myMaxTeleports = oc.getInt("max-num-teleports");
242 42946 : myLogExecutionTime = !oc.getBool("no-duration-log");
243 42946 : myLogStepNumber = !oc.getBool("no-step-log");
244 42946 : myLogStepPeriod = oc.getInt("step-log.period");
245 171784 : myInserter = new MSInsertionControl(*vc, string2time(oc.getString("max-depart-delay")), oc.getBool("eager-insert"), oc.getInt("max-num-vehicles"),
246 171784 : string2time(oc.getString("random-depart-offset")));
247 42946 : myVehicleControl = vc;
248 42946 : myDetectorControl = new MSDetectorControl();
249 42946 : myEdges = nullptr;
250 42946 : myJunctions = nullptr;
251 42946 : myRouteLoaders = nullptr;
252 42946 : myLogics = nullptr;
253 42946 : myPersonControl = nullptr;
254 42946 : myContainerControl = nullptr;
255 42946 : myEdgeWeights = nullptr;
256 42946 : myShapeContainer = shapeCont == nullptr ? new ShapeContainer() : shapeCont;
257 :
258 42946 : myBeginOfTimestepEvents = beginOfTimestepEvents;
259 42946 : myEndOfTimestepEvents = endOfTimestepEvents;
260 42946 : myInsertionEvents = insertionEvents;
261 42946 : myLanesRTree.first = false;
262 :
263 42946 : if (MSGlobals::gUseMesoSim) {
264 14076 : MSGlobals::gMesoNet = new MELoop(string2time(oc.getString("meso-recheck")));
265 : }
266 42946 : myInstance = this;
267 42946 : initStatic();
268 42946 : }
269 :
270 :
271 : void
272 42464 : MSNet::closeBuilding(const OptionsCont& oc, MSEdgeControl* edges, MSJunctionControl* junctions,
273 : SUMORouteLoaderControl* routeLoaders,
274 : MSTLLogicControl* tlc,
275 : std::vector<SUMOTime> stateDumpTimes,
276 : std::vector<std::string> stateDumpFiles,
277 : bool hasInternalLinks,
278 : bool junctionHigherSpeeds,
279 : const MMVersion& version) {
280 42464 : myEdges = edges;
281 42464 : myJunctions = junctions;
282 42464 : myRouteLoaders = routeLoaders;
283 42464 : myLogics = tlc;
284 : // save the time the network state shall be saved at
285 42464 : myStateDumpTimes = stateDumpTimes;
286 42464 : myStateDumpFiles = stateDumpFiles;
287 42464 : myStateDumpPeriod = string2time(oc.getString("save-state.period"));
288 42464 : myStateDumpPrefix = oc.getString("save-state.prefix");
289 42464 : myStateDumpSuffix = oc.getString("save-state.suffix");
290 :
291 : // initialise performance computation
292 42464 : mySimBeginMillis = SysUtils::getCurrentMillis();
293 42464 : myTraCIMillis = 0;
294 42464 : myHasInternalLinks = hasInternalLinks;
295 42464 : myJunctionHigherSpeeds = junctionHigherSpeeds;
296 42464 : myHasElevation = checkElevation();
297 42464 : myHasPedestrianNetwork = checkWalkingarea();
298 42464 : myHasBidiEdges = checkBidiEdges();
299 : myVersion = version;
300 42464 : if ((!MSGlobals::gUsingInternalLanes || !myHasInternalLinks)
301 15099 : && MSGlobals::gWeightsSeparateTurns > 0) {
302 0 : throw ProcessError(TL("Option weights.separate-turns is only supported when simulating with internal lanes"));
303 : }
304 42464 : }
305 :
306 :
307 75717 : MSNet::~MSNet() {
308 42328 : cleanupStatic();
309 : // delete controls
310 42328 : delete myJunctions;
311 42328 : delete myDetectorControl;
312 : // delete mean data
313 42328 : delete myEdges;
314 42328 : delete myInserter;
315 42328 : myInserter = nullptr;
316 42328 : delete myLogics;
317 42328 : delete myRouteLoaders;
318 42328 : if (myPersonControl != nullptr) {
319 8235 : delete myPersonControl;
320 8235 : myPersonControl = nullptr; // just to have that clear for later cleanups
321 : }
322 42328 : if (myContainerControl != nullptr) {
323 1950 : delete myContainerControl;
324 1950 : myContainerControl = nullptr; // just to have that clear for later cleanups
325 : }
326 42328 : delete myVehicleControl; // must happen after deleting transportables
327 : // ShapeContainer registers polygon-update commands with the event controls.
328 : // It must be torn down before the event controls so that ~ShapeContainer
329 : // can still deschedule() its (live) commands; the event controls then
330 : // delete the commands themselves.
331 42328 : delete myShapeContainer;
332 42328 : myShapeContainer = nullptr;
333 : // delete events late so that vehicles can get rid of references first
334 42328 : delete myBeginOfTimestepEvents;
335 42328 : myBeginOfTimestepEvents = nullptr;
336 42328 : delete myEndOfTimestepEvents;
337 42328 : myEndOfTimestepEvents = nullptr;
338 42328 : delete myInsertionEvents;
339 42328 : myInsertionEvents = nullptr;
340 42328 : delete myEdgeWeights;
341 43799 : for (auto& router : myRouterTT) {
342 1471 : delete router.second;
343 : }
344 : myRouterTT.clear();
345 42339 : for (auto& router : myRouterEffort) {
346 11 : delete router.second;
347 : }
348 : myRouterEffort.clear();
349 45154 : for (auto& router : myPedestrianRouter) {
350 2826 : delete router.second;
351 : }
352 : myPedestrianRouter.clear();
353 42328 : resetIntermodalRouter();
354 : myLanesRTree.second.RemoveAll();
355 42345 : for (MSTractionSubstation* sub : myTractionSubstations) {
356 17 : delete sub;
357 : }
358 : myTractionSubstations.clear();
359 42328 : clearAll();
360 42328 : if (MSGlobals::gUseMesoSim) {
361 6938 : delete MSGlobals::gMesoNet;
362 : }
363 42328 : myInstance = nullptr;
364 160373 : }
365 :
366 :
367 : void
368 221 : MSNet::addRestriction(const std::string& id, const SUMOVehicleClass svc, const double speed) {
369 221 : myRestrictions[id][svc] = speed;
370 221 : }
371 :
372 :
373 : const std::map<SUMOVehicleClass, double>*
374 2159863 : MSNet::getRestrictions(const std::string& id) const {
375 : std::map<std::string, std::map<SUMOVehicleClass, double> >::const_iterator i = myRestrictions.find(id);
376 2159863 : if (i == myRestrictions.end()) {
377 : return nullptr;
378 : }
379 1130 : return &i->second;
380 : }
381 :
382 :
383 : double
384 5337 : MSNet::getPreference(const std::string& routingType, const SUMOVTypeParameter& pars) const {
385 5337 : if (gRoutingPreferences) {
386 5337 : auto it = myVTypePreferences.find(pars.id);
387 5337 : if (it != myVTypePreferences.end()) {
388 : auto it2 = it->second.find(routingType);
389 224 : if (it2 != it->second.end()) {
390 56 : return it2->second;
391 : }
392 : }
393 : auto it3 = myVClassPreferences.find(pars.vehicleClass);
394 5281 : if (it3 != myVClassPreferences.end()) {
395 : auto it4 = it3->second.find(routingType);
396 336 : if (it4 != it3->second.end()) {
397 84 : return it4->second;
398 : }
399 : }
400 : // fallback to generel preferences
401 5197 : it = myVTypePreferences.find("");
402 5197 : if (it != myVTypePreferences.end()) {
403 : auto it2 = it->second.find(routingType);
404 4021 : if (it2 != it->second.end()) {
405 1165 : return it2->second;
406 : }
407 : }
408 : }
409 : return 1;
410 : }
411 :
412 :
413 : void
414 28 : MSNet::addPreference(const std::string& routingType, SUMOVehicleClass svc, double prio) {
415 28 : myVClassPreferences[svc][routingType] = prio;
416 28 : gRoutingPreferences = true;
417 28 : }
418 :
419 :
420 : void
421 90 : MSNet::addPreference(const std::string& routingType, std::string vType, double prio) {
422 90 : myVTypePreferences[vType][routingType] = prio;
423 90 : gRoutingPreferences = true;
424 90 : }
425 :
426 : void
427 24 : MSNet::addMesoType(const std::string& typeID, const MESegment::MesoEdgeType& edgeType) {
428 24 : myMesoEdgeTypes[typeID] = edgeType;
429 24 : }
430 :
431 : const MESegment::MesoEdgeType&
432 925560 : MSNet::getMesoType(const std::string& typeID) {
433 : if (myMesoEdgeTypes.count(typeID) == 0) {
434 : // init defaults
435 7550 : const OptionsCont& oc = OptionsCont::getOptions();
436 : MESegment::MesoEdgeType edgeType;
437 7550 : edgeType.tauff = string2time(oc.getString("meso-tauff"));
438 7550 : edgeType.taufj = string2time(oc.getString("meso-taufj"));
439 7550 : edgeType.taujf = string2time(oc.getString("meso-taujf"));
440 7550 : edgeType.taujj = string2time(oc.getString("meso-taujj"));
441 7550 : edgeType.jamThreshold = oc.getFloat("meso-jam-threshold");
442 7550 : edgeType.junctionControl = oc.getBool("meso-junction-control");
443 7550 : edgeType.tlsPenalty = oc.getFloat("meso-tls-penalty");
444 7550 : edgeType.tlsFlowPenalty = oc.getFloat("meso-tls-flow-penalty");
445 7550 : edgeType.minorPenalty = string2time(oc.getString("meso-minor-penalty"));
446 7550 : edgeType.overtaking = oc.getBool("meso-overtaking");
447 7550 : edgeType.edgeLength = oc.getFloat("meso-edgelength");
448 7550 : myMesoEdgeTypes[typeID] = edgeType;
449 : }
450 925560 : return myMesoEdgeTypes[typeID];
451 : }
452 :
453 :
454 : bool
455 7338634 : MSNet::hasFlow(const std::string& id) const {
456 : // inserter is deleted at the end of the simulation
457 7338634 : return myInserter != nullptr && myInserter->hasFlow(id);
458 : }
459 :
460 :
461 : MSNet::SimulationState
462 31963 : MSNet::simulate(SUMOTime start, SUMOTime stop) {
463 : // report the begin when wished
464 63926 : WRITE_MESSAGEF(TL("Simulation version % started with time: %."), VERSION_STRING, time2string(start));
465 : // the simulation loop
466 : SimulationState state = SIMSTATE_RUNNING;
467 : // state loading may have changed the start time so we need to reinit it
468 31963 : myStep = start;
469 : int numSteps = 0;
470 : bool doStepLog = false;
471 125178350 : while (state == SIMSTATE_RUNNING) {
472 125146787 : doStepLog = myLogStepNumber && (numSteps % myLogStepPeriod == 0);
473 : if (doStepLog) {
474 110 : preSimStepOutput();
475 : }
476 125146787 : simulationStep();
477 125146387 : if (doStepLog) {
478 110 : postSimStepOutput();
479 : }
480 125146387 : state = adaptToState(simulationState(stop));
481 : #ifdef DEBUG_SIMSTEP
482 : std::cout << SIMTIME << " MSNet::simulate(" << start << ", " << stop << ")"
483 : << "\n simulation state: " << getStateMessage(state)
484 : << std::endl;
485 : #endif
486 125146387 : numSteps++;
487 : }
488 31563 : if (myLogStepNumber && !doStepLog) {
489 : // ensure some output on the last step
490 17 : preSimStepOutput();
491 17 : postSimStepOutput();
492 : }
493 : // exit simulation loop
494 31563 : if (myLogStepNumber) {
495 : // start new line for final verbose output
496 20 : std::cout << "\n";
497 : }
498 31563 : closeSimulation(start, getStateMessage(state));
499 31563 : return state;
500 : }
501 :
502 :
503 : void
504 138451253 : MSNet::loadRoutes() {
505 138451253 : myRouteLoaders->loadNext(myStep);
506 138450667 : }
507 :
508 :
509 : const std::string
510 13365 : MSNet::generateStatistics(const SUMOTime start, const long now) {
511 13365 : std::ostringstream msg;
512 13365 : if (myLogExecutionTime) {
513 12951 : const long duration = now - mySimBeginMillis;
514 : // print performance notice
515 25902 : msg << "Performance:\n" << " Duration: " << elapsedMs2string(duration) << "\n";
516 12951 : if (duration != 0) {
517 12767 : if (TraCIServer::getInstance() != nullptr) {
518 4299 : msg << " TraCI-Duration: " << elapsedMs2string(myTraCIMillis) << "\n";
519 : }
520 12767 : msg << " Real time factor: " << (STEPS2TIME(myStep - start) * 1000. / (double)duration) << "\n";
521 : msg.setf(std::ios::fixed, std::ios::floatfield); // use decimal format
522 : msg.setf(std::ios::showpoint); // print decimal point
523 12767 : msg << " UPS: " << ((double)myVehiclesMoved / ((double)duration / 1000)) << "\n";
524 12767 : if (myPersonsMoved > 0) {
525 2362 : msg << " UPS-Persons: " << ((double)myPersonsMoved / ((double)duration / 1000)) << "\n";
526 : }
527 : }
528 : // print vehicle statistics
529 12951 : const std::string vehDiscardNotice = ((myVehicleControl->getLoadedVehicleNo() != myVehicleControl->getDepartedVehicleNo()) ?
530 17166 : " (Loaded: " + toString(myVehicleControl->getLoadedVehicleNo()) + ")" : "");
531 : msg << "Vehicles:\n"
532 12951 : << " Inserted: " << myVehicleControl->getDepartedVehicleNo() << vehDiscardNotice << "\n"
533 25902 : << " Running: " << myVehicleControl->getRunningVehicleNo() << "\n"
534 25902 : << " Waiting: " << myInserter->getWaitingVehicleNo() << "\n";
535 :
536 12951 : if (myVehicleControl->getTeleportCount() > 0 || myVehicleControl->getCollisionCount() > 0) {
537 : // print optional teleport statistics
538 : std::vector<std::string> reasons;
539 697 : if (myVehicleControl->getCollisionCount() > 0) {
540 648 : reasons.push_back("Collisions: " + toString(myVehicleControl->getCollisionCount()));
541 : }
542 697 : if (myVehicleControl->getTeleportsJam() > 0) {
543 488 : reasons.push_back("Jam: " + toString(myVehicleControl->getTeleportsJam()));
544 : }
545 697 : if (myVehicleControl->getTeleportsYield() > 0) {
546 240 : reasons.push_back("Yield: " + toString(myVehicleControl->getTeleportsYield()));
547 : }
548 697 : if (myVehicleControl->getTeleportsWrongLane() > 0) {
549 262 : reasons.push_back("Wrong Lane: " + toString(myVehicleControl->getTeleportsWrongLane()));
550 : }
551 2091 : msg << " Teleports: " << myVehicleControl->getTeleportCount() << " (" << joinToString(reasons, ", ") << ")\n";
552 697 : }
553 12951 : if (myVehicleControl->getEmergencyStops() > 0) {
554 66 : msg << " Emergency Stops: " << myVehicleControl->getEmergencyStops() << "\n";
555 : }
556 12951 : if (myVehicleControl->getEmergencyBrakingCount() > 0) {
557 302 : msg << " Emergency Braking: " << myVehicleControl->getEmergencyBrakingCount() << "\n";
558 : }
559 12951 : if (myPersonControl != nullptr && myPersonControl->getLoadedNumber() > 0) {
560 2426 : const std::string discardNotice = ((myPersonControl->getLoadedNumber() != myPersonControl->getDepartedNumber()) ?
561 2804 : " (Loaded: " + toString(myPersonControl->getLoadedNumber()) + ")" : "");
562 : msg << "Persons:\n"
563 2426 : << " Inserted: " << myPersonControl->getDepartedNumber() << discardNotice << "\n"
564 4852 : << " Running: " << myPersonControl->getRunningNumber() << "\n";
565 2426 : if (myPersonControl->getJammedNumber() > 0) {
566 56 : msg << " Jammed: " << myPersonControl->getJammedNumber() << "\n";
567 : }
568 2426 : if (myPersonControl->getTeleportCount() > 0) {
569 : std::vector<std::string> reasons;
570 7 : if (myPersonControl->getTeleportsAbortWait() > 0) {
571 0 : reasons.push_back("Abort Wait: " + toString(myPersonControl->getTeleportsAbortWait()));
572 : }
573 7 : if (myPersonControl->getTeleportsWrongDest() > 0) {
574 14 : reasons.push_back("Wrong Dest: " + toString(myPersonControl->getTeleportsWrongDest()));
575 : }
576 21 : msg << " Teleports: " << myPersonControl->getTeleportCount() << " (" << joinToString(reasons, ", ") << ")\n";
577 7 : }
578 : }
579 12951 : if (myContainerControl != nullptr && myContainerControl->getLoadedNumber() > 0) {
580 76 : const std::string discardNotice = ((myContainerControl->getLoadedNumber() != myContainerControl->getDepartedNumber()) ?
581 76 : " (Loaded: " + toString(myContainerControl->getLoadedNumber()) + ")" : "");
582 : msg << "Containers:\n"
583 76 : << " Inserted: " << myContainerControl->getDepartedNumber() << "\n"
584 152 : << " Running: " << myContainerControl->getRunningNumber() << "\n";
585 76 : if (myContainerControl->getJammedNumber() > 0) {
586 0 : msg << " Jammed: " << myContainerControl->getJammedNumber() << "\n";
587 : }
588 76 : if (myContainerControl->getTeleportCount() > 0) {
589 : std::vector<std::string> reasons;
590 0 : if (myContainerControl->getTeleportsAbortWait() > 0) {
591 0 : reasons.push_back("Abort Wait: " + toString(myContainerControl->getTeleportsAbortWait()));
592 : }
593 0 : if (myContainerControl->getTeleportsWrongDest() > 0) {
594 0 : reasons.push_back("Wrong Dest: " + toString(myContainerControl->getTeleportsWrongDest()));
595 : }
596 0 : msg << " Teleports: " << myContainerControl->getTeleportCount() << " (" << joinToString(reasons, ", ") << ")\n";
597 0 : }
598 : }
599 : }
600 26730 : if (OptionsCont::getOptions().getBool("duration-log.statistics")) {
601 7006 : msg << MSDevice_Tripinfo::printStatistics();
602 : }
603 : std::string result = msg.str();
604 : result.erase(result.end() - 1);
605 13365 : return result;
606 13365 : }
607 :
608 :
609 : void
610 10390 : MSNet::writeCollisions() const {
611 20780 : OutputDevice& od = OutputDevice::getDeviceByOption("collision-output");
612 10543 : for (const auto& item : myCollisions) {
613 306 : for (const auto& c : item.second) {
614 153 : if (c.time != SIMSTEP) {
615 13 : continue;
616 : }
617 280 : od.openTag("collision");
618 140 : od.writeAttr("time", time2string(getCurrentTimeStep()));
619 140 : od.writeAttr("type", c.type);
620 140 : od.writeAttr("lane", c.lane->getID());
621 140 : od.writeAttr("pos", c.pos);
622 140 : od.writeAttr("collider", item.first);
623 140 : od.writeAttr("victim", c.victim);
624 140 : od.writeAttr("colliderType", c.colliderType);
625 140 : od.writeAttr("victimType", c.victimType);
626 140 : od.writeAttr("colliderSpeed", c.colliderSpeed);
627 140 : od.writeAttr("victimSpeed", c.victimSpeed);
628 140 : od.writeAttr("colliderFront", c.colliderFront);
629 140 : od.writeAttr("colliderBack", c.colliderBack);
630 140 : od.writeAttr("victimFront", c.victimFront);
631 140 : od.writeAttr("victimBack", c.victimBack);
632 280 : od.closeTag();
633 : }
634 : }
635 10390 : }
636 :
637 :
638 : void
639 377 : MSNet::writeStatistics(const SUMOTime start, const long now) const {
640 377 : const long duration = now - mySimBeginMillis;
641 377 : OutputDevice& od = OutputDevice::getDeviceByOption("statistic-output");
642 377 : od.openTag("performance");
643 377 : od.writeAttr("clockBegin", time2string(mySimBeginMillis));
644 377 : od.writeAttr("clockEnd", time2string(now));
645 377 : od.writeAttr("clockDuration", time2string(duration));
646 377 : od.writeAttr("traciDuration", time2string(myTraCIMillis));
647 377 : od.writeAttr("realTimeFactor", duration != 0 ? (double)(myStep - start) / (double)duration : -1);
648 377 : od.writeAttr("vehicleUpdatesPerSecond", duration != 0 ? (double)myVehiclesMoved / ((double)duration / 1000) : -1);
649 377 : od.writeAttr("personUpdatesPerSecond", duration != 0 ? (double)myPersonsMoved / ((double)duration / 1000) : -1);
650 377 : od.writeAttr("begin", time2string(start));
651 377 : od.writeAttr("end", time2string(myStep));
652 377 : od.writeAttr("duration", time2string(myStep - start));
653 377 : od.closeTag();
654 377 : od.openTag("vehicles");
655 377 : od.writeAttr("loaded", myVehicleControl->getLoadedVehicleNo());
656 377 : od.writeAttr("inserted", myVehicleControl->getDepartedVehicleNo());
657 377 : od.writeAttr("running", myVehicleControl->getRunningVehicleNo());
658 377 : od.writeAttr("waiting", myInserter->getWaitingVehicleNo());
659 377 : od.closeTag();
660 377 : od.openTag("teleports");
661 377 : od.writeAttr("total", myVehicleControl->getTeleportCount());
662 377 : od.writeAttr("jam", myVehicleControl->getTeleportsJam());
663 377 : od.writeAttr("yield", myVehicleControl->getTeleportsYield());
664 377 : od.writeAttr("wrongLane", myVehicleControl->getTeleportsWrongLane());
665 377 : od.closeTag();
666 377 : od.openTag("safety");
667 377 : od.writeAttr("collisions", myVehicleControl->getCollisionCount());
668 377 : od.writeAttr("emergencyStops", myVehicleControl->getEmergencyStops());
669 377 : od.writeAttr("emergencyBraking", myVehicleControl->getEmergencyBrakingCount());
670 377 : od.closeTag();
671 377 : od.openTag("persons");
672 383 : od.writeAttr("loaded", myPersonControl != nullptr ? myPersonControl->getLoadedNumber() : 0);
673 383 : od.writeAttr("running", myPersonControl != nullptr ? myPersonControl->getRunningNumber() : 0);
674 383 : od.writeAttr("jammed", myPersonControl != nullptr ? myPersonControl->getJammedNumber() : 0);
675 377 : od.closeTag();
676 377 : od.openTag("personTeleports");
677 383 : od.writeAttr("total", myPersonControl != nullptr ? myPersonControl->getTeleportCount() : 0);
678 383 : od.writeAttr("abortWait", myPersonControl != nullptr ? myPersonControl->getTeleportsAbortWait() : 0);
679 383 : od.writeAttr("wrongDest", myPersonControl != nullptr ? myPersonControl->getTeleportsWrongDest() : 0);
680 377 : od.closeTag();
681 599 : if (OptionsCont::getOptions().isSet("tripinfo-output") || OptionsCont::getOptions().getBool("duration-log.statistics")) {
682 264 : MSDevice_Tripinfo::writeStatistics(od);
683 : }
684 377 : }
685 :
686 :
687 : void
688 138450018 : MSNet::writeSummaryOutput(bool finalStep) {
689 : // summary output
690 138450018 : const OptionsCont& oc = OptionsCont::getOptions();
691 138450018 : const bool hasOutput = oc.isSet("summary-output");
692 138450018 : const bool hasPersonOutput = oc.isSet("person-summary-output");
693 138450018 : if (hasOutput || hasPersonOutput) {
694 531916 : const SUMOTime period = string2time(oc.getString("summary-output.period"));
695 531916 : const SUMOTime begin = string2time(oc.getString("begin"));
696 531916 : if ((period > 0 && (myStep - begin) % period != 0 && !finalStep)
697 : // it's the final step but we already wrote output
698 530996 : || (finalStep && (period <= 0 || (myStep - begin) % period == 0))) {
699 : return;
700 : }
701 : }
702 530473 : if (hasOutput) {
703 522721 : OutputDevice& od = OutputDevice::getDeviceByOption("summary-output");
704 522721 : int departedVehiclesNumber = myVehicleControl->getDepartedVehicleNo();
705 522721 : const double meanWaitingTime = departedVehiclesNumber != 0 ? myVehicleControl->getTotalDepartureDelay() / (double) departedVehiclesNumber : -1.;
706 : int endedVehicleNumber = myVehicleControl->getEndedVehicleNo();
707 522721 : const double meanTravelTime = endedVehicleNumber != 0 ? myVehicleControl->getTotalTravelTime() / (double) endedVehicleNumber : -1.;
708 522721 : od.openTag("step");
709 522721 : od.writeAttr("time", time2string(myStep));
710 522721 : od.writeAttr("loaded", myVehicleControl->getLoadedVehicleNo());
711 522721 : od.writeAttr("inserted", myVehicleControl->getDepartedVehicleNo());
712 522721 : od.writeAttr("running", myVehicleControl->getRunningVehicleNo());
713 522721 : od.writeAttr("waiting", myInserter->getWaitingVehicleNo());
714 522721 : od.writeAttr("ended", myVehicleControl->getEndedVehicleNo());
715 522721 : od.writeAttr("arrived", myVehicleControl->getArrivedVehicleNo());
716 522721 : od.writeAttr("collisions", myVehicleControl->getCollisionCount());
717 522721 : od.writeAttr("teleports", myVehicleControl->getTeleportCount());
718 522721 : od.writeAttr("halting", myVehicleControl->getHaltingVehicleNo());
719 522721 : od.writeAttr("stopped", myVehicleControl->getStoppedVehiclesCount());
720 522721 : od.writeAttr("meanWaitingTime", meanWaitingTime);
721 522721 : od.writeAttr("meanTravelTime", meanTravelTime);
722 522721 : std::pair<double, double> meanSpeed = myVehicleControl->getVehicleMeanSpeeds();
723 522721 : od.writeAttr("meanSpeed", meanSpeed.first);
724 522721 : od.writeAttr("meanSpeedRelative", meanSpeed.second);
725 522721 : od.writeAttr("discarded", myVehicleControl->getDiscardedVehicleNo());
726 522721 : if (myLogExecutionTime) {
727 235433 : od.writeAttr("duration", mySimStepDuration);
728 : }
729 1045442 : od.closeTag();
730 : }
731 138448575 : if (hasPersonOutput) {
732 7752 : OutputDevice& od = OutputDevice::getDeviceByOption("person-summary-output");
733 7752 : MSTransportableControl& pc = getPersonControl();
734 7752 : od.openTag("step");
735 15504 : od.writeAttr("time", time2string(myStep));
736 7752 : od.writeAttr("loaded", pc.getLoadedNumber());
737 7752 : od.writeAttr("inserted", pc.getDepartedNumber());
738 7752 : od.writeAttr("walking", pc.getMovingNumber());
739 7752 : od.writeAttr("waitingForRide", pc.getWaitingForVehicleNumber());
740 7752 : od.writeAttr("riding", pc.getRidingNumber());
741 7752 : od.writeAttr("stopping", pc.getWaitingUntilNumber());
742 7752 : od.writeAttr("jammed", pc.getJammedNumber());
743 7752 : od.writeAttr("ended", pc.getEndedNumber());
744 7752 : od.writeAttr("arrived", pc.getArrivedNumber());
745 7752 : od.writeAttr("teleports", pc.getTeleportCount());
746 7752 : od.writeAttr("discarded", pc.getDiscardedNumber());
747 7752 : if (myLogExecutionTime) {
748 0 : od.writeAttr("duration", mySimStepDuration);
749 : }
750 15504 : od.closeTag();
751 : }
752 : }
753 :
754 :
755 : void
756 40817 : MSNet::closeSimulation(SUMOTime start, const std::string& reason) {
757 : // report the end when wished
758 81634 : WRITE_MESSAGE(TLF("Simulation ended at time: %.", time2string(getCurrentTimeStep())));
759 40817 : if (reason != "") {
760 80752 : WRITE_MESSAGE(TL("Reason: ") + reason);
761 : }
762 40817 : myDetectorControl->close(myStep);
763 81634 : if (OptionsCont::getOptions().isSet("queue-output")) {
764 358 : MSQueueExport::finish(OutputDevice::getDeviceByOption("queue-output"), myStep);
765 : }
766 42278 : if (MSStopOut::active() && OptionsCont::getOptions().getBool("stop-output.write-unfinished")) {
767 122 : MSStopOut::getInstance()->generateOutputForUnfinished();
768 : }
769 40817 : MSDevice_Vehroutes::writePendingOutput(OptionsCont::getOptions().getBool("vehroute-output.write-unfinished"));
770 81634 : if (OptionsCont::getOptions().getBool("tripinfo-output.write-unfinished")) {
771 1110 : MSDevice_Tripinfo::generateOutputForUnfinished();
772 : }
773 81634 : if (OptionsCont::getOptions().isSet("chargingstations-output")) {
774 252 : if (!OptionsCont::getOptions().getBool("chargingstations-output.aggregated")) {
775 106 : writeChargingStationOutput();
776 40 : } else if (OptionsCont::getOptions().getBool("chargingstations-output.aggregated.write-unfinished")) {
777 12 : MSChargingStationExport::write(OutputDevice::getDeviceByOption("chargingstations-output"), true);
778 : }
779 : }
780 81634 : if (OptionsCont::getOptions().isSet("overheadwiresegments-output")) {
781 5 : writeOverheadWireSegmentOutput();
782 : }
783 81634 : if (OptionsCont::getOptions().isSet("substations-output")) {
784 5 : writeSubstationOutput();
785 : }
786 40817 : writeRailSignalBlocks();
787 40817 : const long now = SysUtils::getCurrentMillis();
788 68683 : if (myLogExecutionTime || OptionsCont::getOptions().getBool("duration-log.statistics")) {
789 26730 : WRITE_MESSAGE(generateStatistics(start, now));
790 : }
791 81634 : if (OptionsCont::getOptions().isSet("statistic-output")) {
792 377 : writeStatistics(start, now);
793 : }
794 : // maybe write a final line of output if reporting is periodic
795 40817 : writeSummaryOutput(true);
796 40817 : }
797 :
798 :
799 : void
800 138412384 : MSNet::simulationStep(const bool onlyMove) {
801 138412384 : if (myStepCompletionMissing) {
802 4 : postMoveStep();
803 4 : myStepCompletionMissing = false;
804 2663 : return;
805 : }
806 : #ifdef DEBUG_SIMSTEP
807 : std::cout << SIMTIME << ": MSNet::simulationStep() called"
808 : << ", myStep = " << myStep
809 : << std::endl;
810 : #endif
811 : TraCIServer* t = TraCIServer::getInstance();
812 : int lastTraCICmd = 0;
813 138412380 : if (t != nullptr) {
814 12362827 : if (myLogExecutionTime) {
815 12165860 : myTraCIStepDuration = SysUtils::getCurrentMillis();
816 : }
817 12362827 : lastTraCICmd = t->processCommands(myStep);
818 : #ifdef DEBUG_SIMSTEP
819 : bool loadRequested = !TraCI::getLoadArgs().empty();
820 : assert(t->getTargetTime() >= myStep || loadRequested || TraCIServer::wasClosed());
821 : #endif
822 12362723 : if (myLogExecutionTime) {
823 12165783 : myTraCIStepDuration = SysUtils::getCurrentMillis() - myTraCIStepDuration;
824 : }
825 12362723 : if (TraCIServer::wasClosed() || !t->getLoadArgs().empty()) {
826 : return;
827 : }
828 : }
829 : #ifdef DEBUG_SIMSTEP
830 : std::cout << SIMTIME << ": TraCI target time: " << t->getTargetTime() << std::endl;
831 : #endif
832 : // execute beginOfTimestepEvents
833 138409621 : if (myLogExecutionTime) {
834 100243134 : mySimStepDuration = SysUtils::getCurrentMillis();
835 : }
836 : // simulation state output
837 138409621 : std::vector<SUMOTime>::iterator timeIt = std::find(myStateDumpTimes.begin(), myStateDumpTimes.end(), myStep);
838 138409621 : if (timeIt != myStateDumpTimes.end()) {
839 375 : const int dist = (int)distance(myStateDumpTimes.begin(), timeIt);
840 375 : MSStateHandler::saveState(myStateDumpFiles[dist], myStep);
841 : }
842 138409621 : if (myStateDumpPeriod > 0 && myStep % myStateDumpPeriod == 0) {
843 84 : std::string timeStamp = time2string(myStep);
844 : std::replace(timeStamp.begin(), timeStamp.end(), ':', '-');
845 84 : const std::string filename = myStateDumpPrefix + "_" + timeStamp + myStateDumpSuffix;
846 84 : MSStateHandler::saveState(filename, myStep);
847 84 : myPeriodicStateFiles.push_back(filename);
848 84 : int keep = OptionsCont::getOptions().getInt("save-state.period.keep");
849 84 : if (keep > 0 && (int)myPeriodicStateFiles.size() > keep) {
850 0 : std::remove(myPeriodicStateFiles.front().c_str());
851 : myPeriodicStateFiles.erase(myPeriodicStateFiles.begin());
852 : }
853 : }
854 138409621 : myBeginOfTimestepEvents->execute(myStep);
855 138409613 : if (MSRailSignalControl::hasInstance()) {
856 10190680 : MSRailSignalControl::getInstance().updateSignals(myStep);
857 : }
858 : #ifdef HAVE_FOX
859 138409613 : MSRoutingEngine::waitForAll();
860 : #endif
861 138409613 : if (MSGlobals::gCheck4Accidents && !MSGlobals::gUseMesoSim) {
862 115157038 : myEdges->detectCollisions(myStep, STAGE_EVENTS);
863 : }
864 : // check whether the tls programs need to be switched
865 138409613 : myLogics->check2Switch(myStep);
866 :
867 138409613 : if (MSGlobals::gUseMesoSim) {
868 23252575 : MSGlobals::gMesoNet->simulate(myStep);
869 : } else {
870 : // assure all lanes with vehicles are 'active'
871 115157038 : myEdges->patchActiveLanes();
872 :
873 : // compute safe velocities for all vehicles for the next few lanes
874 : // also register ApproachingVehicleInformation for all links
875 115157038 : myEdges->planMovements(myStep);
876 :
877 : // register junction approaches based on planned velocities as basis for right-of-way decision
878 115157038 : myEdges->setJunctionApproaches();
879 :
880 : // decide right-of-way and execute movements
881 115157038 : myEdges->executeMovements(myStep);
882 115157035 : if (MSGlobals::gCheck4Accidents) {
883 115157035 : myEdges->detectCollisions(myStep, STAGE_MOVEMENTS);
884 : }
885 :
886 : // vehicles may change lanes
887 115157035 : myEdges->changeLanes(myStep);
888 :
889 115157035 : if (MSGlobals::gCheck4Accidents) {
890 115157035 : myEdges->detectCollisions(myStep, STAGE_LANECHANGE);
891 : }
892 : }
893 : // flush arrived meso vehicles and micro vehicles that were removed due to collision
894 138409610 : myVehicleControl->removePending();
895 138409610 : loadRoutes();
896 :
897 : // persons
898 138409594 : if (myPersonControl != nullptr && myPersonControl->hasTransportables()) {
899 76456642 : myPersonControl->checkWaiting(this, myStep);
900 : }
901 : // containers
902 138409546 : if (myContainerControl != nullptr && myContainerControl->hasTransportables()) {
903 4821155 : myContainerControl->checkWaiting(this, myStep);
904 : }
905 : #ifdef HAVE_FOX
906 138409546 : MSRoutingEngine::waitForAll();
907 138409546 : if (myPersonControl != nullptr) {
908 78185628 : myPersonControl->processPendingRouting(this, myStep);
909 : }
910 138409538 : if (myContainerControl != nullptr) {
911 4882183 : myContainerControl->processPendingRouting(this, myStep);
912 : }
913 : #endif
914 138409538 : if (MSRailSignalControl::hasInstance()) {
915 10190680 : MSRailSignalControl::getInstance().resetWaitRelations();
916 : // preserve waitRelation from insertion for the next step
917 : }
918 : // insert vehicles
919 138409538 : myInserter->determineCandidates(myStep);
920 138409491 : myInsertionEvents->execute(myStep);
921 : #ifdef HAVE_FOX
922 138409396 : MSRoutingEngine::waitForAll();
923 : #endif
924 138409372 : myInserter->emitVehicles(myStep);
925 138409226 : if (MSGlobals::gCheck4Accidents && !MSGlobals::gUseMesoSim) {
926 : //myEdges->patchActiveLanes(); // @note required to detect collisions on lanes that were empty before insertion. wasteful?
927 115156759 : myEdges->detectCollisions(myStep, STAGE_INSERTIONS);
928 : }
929 138409226 : MSVehicleTransfer::getInstance()->checkInsertions(myStep);
930 :
931 : // execute endOfTimestepEvents
932 138409226 : myEndOfTimestepEvents->execute(myStep);
933 :
934 138409216 : if (myLogExecutionTime) {
935 100242960 : myTraCIStepDuration -= SysUtils::getCurrentMillis();
936 : }
937 138409216 : if (onlyMove) {
938 4 : myStepCompletionMissing = true;
939 4 : return;
940 : }
941 138409212 : if (t != nullptr && lastTraCICmd == libsumo::CMD_EXECUTEMOVE) {
942 6 : t->processCommands(myStep, true);
943 : }
944 138409212 : postMoveStep();
945 : }
946 :
947 :
948 : void
949 138409216 : MSNet::postMoveStep() {
950 138409216 : const int numControlled = libsumo::Helper::postProcessRemoteControl();
951 138409216 : if (numControlled > 0 && MSGlobals::gCheck4Accidents) {
952 2213821 : myEdges->detectCollisions(myStep, STAGE_REMOTECONTROL);
953 : }
954 138409216 : if (myLogExecutionTime) {
955 100242960 : myTraCIStepDuration += SysUtils::getCurrentMillis();
956 100242960 : myTraCIMillis += myTraCIStepDuration;
957 : }
958 138409216 : if (MSGlobals::gCheck4Accidents && !MSGlobals::gUseMesoSim) {
959 : // collisions from the previous step were kept to avoid duplicate
960 : // warnings. we must remove them now to ensure correct output.
961 115156754 : removeOutdatedCollisions();
962 : }
963 : // update and write (if needed) detector values
964 138409216 : mySimStepDuration = SysUtils::getCurrentMillis() - mySimStepDuration;
965 138409216 : writeOutput();
966 :
967 138409200 : if (myLogExecutionTime) {
968 100242960 : myVehiclesMoved += myVehicleControl->getRunningVehicleNo();
969 100242960 : if (myPersonControl != nullptr) {
970 75654297 : myPersonsMoved += myPersonControl->getRunningNumber();
971 : }
972 : }
973 138409200 : myStep += DELTA_T;
974 138409200 : }
975 :
976 :
977 : MSNet::SimulationState
978 138313447 : MSNet::simulationState(SUMOTime stopTime) const {
979 138313447 : if (TraCIServer::wasClosed()) {
980 : return SIMSTATE_CONNECTION_CLOSED;
981 : }
982 138310669 : if (TraCIServer::getInstance() != nullptr && !TraCIServer::getInstance()->getLoadArgs().empty()) {
983 : return SIMSTATE_LOADING;
984 : }
985 138310656 : if ((stopTime < 0 || myStep > stopTime) && TraCIServer::getInstance() == nullptr && (stopTime > 0 || myStep > myEdgeDataEndTime)) {
986 104507752 : if ((myVehicleControl->getActiveVehicleCount() == 0)
987 76848379 : && (myInserter->getPendingFlowCount() == 0)
988 72654841 : && (myPersonControl == nullptr || !myPersonControl->hasNonWaiting())
989 412347 : && (myContainerControl == nullptr || !myContainerControl->hasNonWaiting())
990 104570885 : && !MSDevice_Taxi::hasServableReservations()) {
991 : return SIMSTATE_NO_FURTHER_VEHICLES;
992 : }
993 : }
994 138264389 : if (stopTime >= 0 && myStep >= stopTime) {
995 : return SIMSTATE_END_STEP_REACHED;
996 : }
997 138243278 : if (myMaxTeleports >= 0 && myVehicleControl->getTeleportCount() > myMaxTeleports) {
998 : return SIMSTATE_TOO_MANY_TELEPORTS;
999 : }
1000 138243270 : if (myAmInterrupted) {
1001 8 : return SIMSTATE_INTERRUPTED;
1002 : }
1003 : return SIMSTATE_RUNNING;
1004 : }
1005 :
1006 :
1007 : MSNet::SimulationState
1008 138304799 : MSNet::adaptToState(MSNet::SimulationState state, const bool isLibsumo) const {
1009 138304799 : if (state == SIMSTATE_LOADING) {
1010 13 : OptionsIO::setArgs(TraCIServer::getInstance()->getLoadArgs());
1011 : TraCIServer::getInstance()->getLoadArgs().clear();
1012 138304786 : } else if (state != SIMSTATE_RUNNING && ((TraCIServer::getInstance() != nullptr && !TraCIServer::wasClosed()) || isLibsumo)) {
1013 : // overrides SIMSTATE_END_STEP_REACHED, e.g. (TraCI / Libsumo ignore SUMO's --end option)
1014 22573 : return SIMSTATE_RUNNING;
1015 138282213 : } else if (state == SIMSTATE_NO_FURTHER_VEHICLES) {
1016 28479 : if (myPersonControl != nullptr) {
1017 6873 : myPersonControl->abortAnyWaitingForVehicle();
1018 : }
1019 28479 : if (myContainerControl != nullptr) {
1020 1863 : myContainerControl->abortAnyWaitingForVehicle();
1021 : }
1022 28479 : myVehicleControl->abortWaiting();
1023 : }
1024 : return state;
1025 : }
1026 :
1027 :
1028 : std::string
1029 40211 : MSNet::getStateMessage(MSNet::SimulationState state) {
1030 40211 : switch (state) {
1031 : case MSNet::SIMSTATE_RUNNING:
1032 441 : return "";
1033 : case MSNet::SIMSTATE_END_STEP_REACHED:
1034 8261 : return TL("The final simulation step has been reached.");
1035 : case MSNet::SIMSTATE_NO_FURTHER_VEHICLES:
1036 28840 : return TL("All vehicles have left the simulation.");
1037 : case MSNet::SIMSTATE_CONNECTION_CLOSED:
1038 2642 : return TL("TraCI requested termination.");
1039 : case MSNet::SIMSTATE_ERROR_IN_SIM:
1040 0 : return TL("An error occurred (see log).");
1041 : case MSNet::SIMSTATE_INTERRUPTED:
1042 8 : return TL("Interrupted.");
1043 : case MSNet::SIMSTATE_TOO_MANY_TELEPORTS:
1044 6 : return TL("Too many teleports.");
1045 : case MSNet::SIMSTATE_LOADING:
1046 13 : return TL("TraCI issued load command.");
1047 : default:
1048 0 : return TL("Unknown reason.");
1049 : }
1050 : }
1051 :
1052 :
1053 : void
1054 42619 : MSNet::clearAll() {
1055 : // clear container
1056 42619 : MSEdge::clear();
1057 42619 : MSLane::clear();
1058 42619 : MSRoute::clear();
1059 42619 : delete MSVehicleTransfer::getInstance();
1060 42619 : MSDevice::cleanupAll();
1061 42619 : MSCalibrator::cleanup();
1062 85738 : while (!MSLaneSpeedTrigger::getInstances().empty()) {
1063 500 : delete MSLaneSpeedTrigger::getInstances().begin()->second;
1064 : }
1065 46816 : while (!MSTriggeredRerouter::getInstances().empty()) {
1066 4197 : delete MSTriggeredRerouter::getInstances().begin()->second;
1067 : }
1068 42619 : MSDevice_BTsender::cleanup();
1069 42619 : MSDevice_SSM::cleanup();
1070 42619 : MSDevice_ToC::cleanup();
1071 42619 : MSStopOut::cleanup();
1072 42619 : MSRailSignalConstraint::cleanup();
1073 42619 : MSRailSignalControl::cleanup();
1074 42619 : MSDriveWay::cleanup();
1075 : TraCIServer* t = TraCIServer::getInstance();
1076 42619 : if (t != nullptr) {
1077 2760 : t->cleanup();
1078 : }
1079 42619 : libsumo::Helper::cleanup();
1080 42619 : OutputDevice::closeAll(true);
1081 42619 : }
1082 :
1083 :
1084 : void
1085 162 : MSNet::clearState(const SUMOTime step, bool quickReload) {
1086 162 : MSGlobals::gClearState = true;
1087 162 : if (MSGlobals::gUseMesoSim) {
1088 12 : MSGlobals::gMesoNet->clearState();
1089 390 : for (MSEdge* const edge : MSEdge::getAllEdges()) {
1090 776 : for (MESegment* s = MSGlobals::gMesoNet->getSegmentForEdge(*edge); s != nullptr; s = s->getNextSegment()) {
1091 398 : s->clearState();
1092 : }
1093 : }
1094 : } else {
1095 7110 : for (MSEdge* const edge : MSEdge::getAllEdges()) {
1096 15408 : for (MSLane* const lane : edge->getLanes()) {
1097 8448 : lane->getVehiclesSecure();
1098 8448 : lane->clearState();
1099 8448 : lane->releaseVehicles();
1100 : }
1101 6960 : edge->clearState();
1102 : }
1103 : }
1104 162 : myInserter->clearState();
1105 : // detectors may still reference persons/vehicles
1106 162 : myDetectorControl->updateDetectors(myStep);
1107 162 : myDetectorControl->writeOutput(myStep, true);
1108 162 : myDetectorControl->clearState(step);
1109 :
1110 162 : if (myPersonControl != nullptr) {
1111 18 : myPersonControl->clearState();
1112 : }
1113 162 : if (myContainerControl != nullptr) {
1114 0 : myContainerControl->clearState();
1115 : }
1116 : // delete vtypes after transportables have removed their types
1117 162 : myVehicleControl->clearState(true);
1118 162 : MSVehicleTransfer::getInstance()->clearState();
1119 162 : myLogics->clearState(step, quickReload);
1120 : // delete all routes after vehicles and detector output is done
1121 162 : MSRoute::dict_clearState();
1122 203 : for (auto& item : myStoppingPlaces) {
1123 82 : for (auto& item2 : item.second) {
1124 41 : item2.second->clearState();
1125 : }
1126 : }
1127 162 : myShapeContainer->clearState();
1128 162 : myBeginOfTimestepEvents->clearState(myStep, step);
1129 162 : myEndOfTimestepEvents->clearState(myStep, step);
1130 162 : myInsertionEvents->clearState(myStep, step);
1131 162 : MSRailSignalControl::clearState();
1132 162 : MSDriveWay::clearState();
1133 162 : myStep = step;
1134 162 : MSGlobals::gClearState = false;
1135 162 : }
1136 :
1137 :
1138 : SUMOTime
1139 570 : MSNet::getLoaderTime() const {
1140 570 : return myRouteLoaders->getCurrentLoadTime();
1141 : }
1142 :
1143 : void
1144 710 : MSNet::setLoaderTime(SUMOTime time) {
1145 710 : myRouteLoaders->setCurrentLoadTime(time);
1146 710 : myStateLoaderTime = MAX2(myStateLoaderTime, time);
1147 710 : }
1148 :
1149 : void
1150 138409216 : MSNet::writeOutput() {
1151 : // update detector values
1152 138409216 : myDetectorControl->updateDetectors(myStep);
1153 138409207 : const OptionsCont& oc = OptionsCont::getOptions();
1154 :
1155 : // check state dumps
1156 276818414 : if (oc.isSet("netstate-dump")) {
1157 12936 : MSXMLRawOut::write(OutputDevice::getDeviceByOption("netstate-dump"), *myEdges, myStep,
1158 : oc.getInt("netstate-dump.precision"));
1159 : }
1160 :
1161 : // check fcd dumps
1162 276818414 : if (OptionsCont::getOptions().isSet("fcd-output")) {
1163 14578106 : if (OptionsCont::getOptions().isSet("person-fcd-output")) {
1164 24 : MSFCDExport::write(OutputDevice::getDeviceByOption("fcd-output"), myStep, SUMO_TAG_VEHICLE);
1165 48 : MSFCDExport::write(OutputDevice::getDeviceByOption("person-fcd-output"), myStep, SUMO_TAG_PERSON);
1166 : } else {
1167 14578058 : MSFCDExport::write(OutputDevice::getDeviceByOption("fcd-output"), myStep);
1168 : }
1169 : }
1170 :
1171 : // check emission dumps
1172 276818414 : if (OptionsCont::getOptions().isSet("emission-output")) {
1173 215992 : MSEmissionExport::write(OutputDevice::getDeviceByOption("emission-output"), myStep);
1174 : }
1175 :
1176 : // battery dumps
1177 276818414 : if (OptionsCont::getOptions().isSet("battery-output")) {
1178 148254 : MSBatteryExport::write(OutputDevice::getDeviceByOption("battery-output"), myStep,
1179 : oc.getInt("battery-output.precision"));
1180 : }
1181 :
1182 : // charging station aggregated dumps
1183 138500321 : if (OptionsCont::getOptions().isSet("chargingstations-output") && OptionsCont::getOptions().getBool("chargingstations-output.aggregated")) {
1184 22248 : MSChargingStationExport::write(OutputDevice::getDeviceByOption("chargingstations-output"));
1185 : }
1186 :
1187 : // elecHybrid dumps
1188 276818414 : if (OptionsCont::getOptions().isSet("elechybrid-output")) {
1189 450 : std::string output = OptionsCont::getOptions().getString("elechybrid-output");
1190 :
1191 900 : if (oc.getBool("elechybrid-output.aggregated")) {
1192 : // build a xml file with aggregated device.elechybrid output
1193 600 : MSElecHybridExport::writeAggregated(OutputDevice::getDeviceByOption("elechybrid-output"), myStep,
1194 : oc.getInt("elechybrid-output.precision"));
1195 : } else {
1196 : // build a separate xml file for each vehicle equipped with device.elechybrid
1197 : // RICE_TODO: Does this have to be placed here in MSNet.cpp ?
1198 150 : MSVehicleControl& vc = MSNet::getInstance()->getVehicleControl();
1199 204 : for (MSVehicleControl::constVehIt it = vc.loadedVehBegin(); it != vc.loadedVehEnd(); ++it) {
1200 54 : const SUMOVehicle* veh = it->second;
1201 54 : if (!veh->isOnRoad()) {
1202 0 : continue;
1203 : }
1204 54 : if (static_cast<MSDevice_ElecHybrid*>(veh->getDevice(typeid(MSDevice_ElecHybrid))) != nullptr) {
1205 : std::string vehID = veh->getID();
1206 54 : std::string filename2 = output + "_" + vehID + ".xml";
1207 54 : OutputDevice& dev = OutputDevice::getDevice(filename2);
1208 : std::map<SumoXMLAttr, std::string> attrs;
1209 54 : attrs[SUMO_ATTR_VEHICLE] = vehID;
1210 54 : attrs[SUMO_ATTR_MAXIMUMBATTERYCAPACITY] = toString(dynamic_cast<MSDevice_ElecHybrid*>(veh->getDevice(typeid(MSDevice_ElecHybrid)))->getMaximumBatteryCapacity());
1211 54 : attrs[SUMO_ATTR_RECUPERATIONENABLE] = toString(MSGlobals::gOverheadWireRecuperation);
1212 108 : dev.writeXMLHeader("elecHybrid-export", "", attrs);
1213 108 : MSElecHybridExport::write(OutputDevice::getDevice(filename2), veh, myStep, oc.getInt("elechybrid-output.precision"));
1214 : }
1215 : }
1216 : }
1217 : }
1218 :
1219 :
1220 : // check full dumps
1221 276818414 : if (OptionsCont::getOptions().isSet("full-output")) {
1222 1138 : MSGlobals::gHaveEmissions = true;
1223 2276 : MSFullExport::write(OutputDevice::getDeviceByOption("full-output"), myStep);
1224 : }
1225 :
1226 : // check queue dumps
1227 276818414 : if (OptionsCont::getOptions().isSet("queue-output")) {
1228 330534 : MSQueueExport::write(OutputDevice::getDeviceByOption("queue-output"), myStep);
1229 : }
1230 :
1231 : // check amitran dumps
1232 276818414 : if (OptionsCont::getOptions().isSet("amitran-output")) {
1233 2040 : MSAmitranTrajectories::write(OutputDevice::getDeviceByOption("amitran-output"), myStep);
1234 : }
1235 :
1236 : // check vtk dumps
1237 276818414 : if (OptionsCont::getOptions().isSet("vtk-output")) {
1238 :
1239 60 : if (MSNet::getInstance()->getVehicleControl().getRunningVehicleNo() > 0) {
1240 60 : std::string timestep = time2string(myStep);
1241 60 : if (TS >= 1.0) {
1242 48 : timestep = timestep.substr(0, timestep.length() - 3);
1243 36 : } else if (DELTA_T % 100 == 0) {
1244 72 : timestep = timestep.substr(0, timestep.length() - 1);
1245 : }
1246 66 : std::string output = OptionsCont::getOptions().getString("vtk-output");
1247 66 : std::string filename = output + "_" + timestep + ".vtp";
1248 :
1249 60 : OutputDevice_File dev(filename);
1250 :
1251 : //build a huge mass of xml files
1252 54 : MSVTKExport::write(dev, myStep);
1253 :
1254 54 : }
1255 :
1256 : }
1257 :
1258 138409201 : writeSummaryOutput();
1259 :
1260 : // write detector values
1261 138409201 : myDetectorControl->writeOutput(myStep + DELTA_T, false);
1262 :
1263 : // write link states
1264 276818400 : if (OptionsCont::getOptions().isSet("link-output")) {
1265 4048 : OutputDevice& od = OutputDevice::getDeviceByOption("link-output");
1266 4048 : od.openTag("timestep");
1267 4048 : od.writeAttr(SUMO_ATTR_ID, STEPS2TIME(myStep));
1268 85848 : for (const MSEdge* const edge : myEdges->getEdges()) {
1269 180200 : for (const MSLane* const lane : edge->getLanes()) {
1270 212304 : for (const MSLink* const link : lane->getLinkCont()) {
1271 227808 : link->writeApproaching(od, lane->getID());
1272 : }
1273 : }
1274 : }
1275 8096 : od.closeTag();
1276 : }
1277 :
1278 : // write SSM output
1279 140942262 : for (MSDevice_SSM* dev : MSDevice_SSM::getInstances()) {
1280 2533062 : dev->updateAndWriteOutput();
1281 : }
1282 :
1283 : // write ToC output
1284 138424919 : for (MSDevice_ToC* dev : MSDevice_ToC::getInstances()) {
1285 15719 : if (dev->generatesOutput()) {
1286 15513 : dev->writeOutput();
1287 : }
1288 : }
1289 :
1290 276818400 : if (OptionsCont::getOptions().isSet("collision-output")) {
1291 10390 : writeCollisions();
1292 : }
1293 138409200 : }
1294 :
1295 :
1296 : bool
1297 0 : MSNet::logSimulationDuration() const {
1298 0 : return myLogExecutionTime;
1299 : }
1300 :
1301 :
1302 : MSTransportableControl&
1303 30590359 : MSNet::getPersonControl() {
1304 30590359 : if (myPersonControl == nullptr) {
1305 6684 : myPersonControl = new MSTransportableControl(true);
1306 : }
1307 30590335 : return *myPersonControl;
1308 : }
1309 :
1310 :
1311 : MSTransportableControl&
1312 8820240 : MSNet::getContainerControl() {
1313 8820240 : if (myContainerControl == nullptr) {
1314 1782 : myContainerControl = new MSTransportableControl(false);
1315 : }
1316 8820240 : return *myContainerControl;
1317 : }
1318 :
1319 : MSDynamicShapeUpdater*
1320 23 : MSNet::makeDynamicShapeUpdater() {
1321 23 : myDynamicShapeUpdater = std::unique_ptr<MSDynamicShapeUpdater> (new MSDynamicShapeUpdater(*myShapeContainer));
1322 23 : return myDynamicShapeUpdater.get();
1323 : }
1324 :
1325 : MSEdgeWeightsStorage&
1326 7051655 : MSNet::getWeightsStorage() {
1327 7051655 : if (myEdgeWeights == nullptr) {
1328 1961 : myEdgeWeights = new MSEdgeWeightsStorage();
1329 : }
1330 7051655 : return *myEdgeWeights;
1331 : }
1332 :
1333 :
1334 : void
1335 127 : MSNet::preSimStepOutput() const {
1336 127 : std::cout << "Step #" << time2string(myStep);
1337 127 : }
1338 :
1339 :
1340 : void
1341 127 : MSNet::postSimStepOutput() const {
1342 127 : if (myLogExecutionTime) {
1343 125 : std::ostringstream oss;
1344 : oss.setf(std::ios::fixed, std::ios::floatfield); // use decimal format
1345 : oss.setf(std::ios::showpoint); // print decimal point
1346 125 : oss << std::setprecision(gPrecision);
1347 125 : if (mySimStepDuration != 0) {
1348 71 : const double durationSec = (double)mySimStepDuration / 1000.;
1349 71 : oss << " (" << mySimStepDuration << "ms ~= "
1350 71 : << (TS / durationSec) << "*RT, ~"
1351 71 : << ((double) myVehicleControl->getRunningVehicleNo() / durationSec);
1352 : } else {
1353 54 : oss << " (0ms ?*RT. ?";
1354 : }
1355 125 : oss << "UPS, ";
1356 125 : if (TraCIServer::getInstance() != nullptr) {
1357 79 : oss << "TraCI: " << myTraCIStepDuration << "ms, ";
1358 : }
1359 125 : oss << "vehicles TOT " << myVehicleControl->getDepartedVehicleNo()
1360 250 : << " ACT " << myVehicleControl->getRunningVehicleNo()
1361 125 : << " BUF " << myInserter->getWaitingVehicleNo()
1362 125 : << ") ";
1363 250 : std::string prev = "Step #" + time2string(myStep - DELTA_T);
1364 250 : std::cout << oss.str().substr(0, 90 - prev.length());
1365 125 : }
1366 127 : std::cout << '\r';
1367 127 : }
1368 :
1369 :
1370 : void
1371 11602 : MSNet::addVehicleStateListener(VehicleStateListener* listener) {
1372 11602 : if (find(myVehicleStateListeners.begin(), myVehicleStateListeners.end(), listener) == myVehicleStateListeners.end()) {
1373 11602 : myVehicleStateListeners.push_back(listener);
1374 : }
1375 11602 : }
1376 :
1377 :
1378 : void
1379 58 : MSNet::removeVehicleStateListener(VehicleStateListener* listener) {
1380 58 : std::vector<VehicleStateListener*>::iterator i = std::find(myVehicleStateListeners.begin(), myVehicleStateListeners.end(), listener);
1381 58 : if (i != myVehicleStateListeners.end()) {
1382 58 : myVehicleStateListeners.erase(i);
1383 : }
1384 58 : }
1385 :
1386 :
1387 : void
1388 16035833 : MSNet::informVehicleStateListener(const SUMOVehicle* const vehicle, VehicleState to, const std::string& info) {
1389 : #ifdef HAVE_FOX
1390 16035833 : ScopedLocker<> lock(myVehicleStateListenerMutex, MSGlobals::gNumThreads > 1);
1391 : #endif
1392 16728211 : for (VehicleStateListener* const listener : myVehicleStateListeners) {
1393 692378 : listener->vehicleStateChanged(vehicle, to, info);
1394 : }
1395 16035833 : }
1396 :
1397 :
1398 : void
1399 3908 : MSNet::addTransportableStateListener(TransportableStateListener* listener) {
1400 3908 : if (find(myTransportableStateListeners.begin(), myTransportableStateListeners.end(), listener) == myTransportableStateListeners.end()) {
1401 3908 : myTransportableStateListeners.push_back(listener);
1402 : }
1403 3908 : }
1404 :
1405 :
1406 : void
1407 0 : MSNet::removeTransportableStateListener(TransportableStateListener* listener) {
1408 0 : std::vector<TransportableStateListener*>::iterator i = std::find(myTransportableStateListeners.begin(), myTransportableStateListeners.end(), listener);
1409 0 : if (i != myTransportableStateListeners.end()) {
1410 0 : myTransportableStateListeners.erase(i);
1411 : }
1412 0 : }
1413 :
1414 :
1415 : void
1416 1009687 : MSNet::informTransportableStateListener(const MSTransportable* const transportable, TransportableState to, const std::string& info) {
1417 : #ifdef HAVE_FOX
1418 1009687 : ScopedLocker<> lock(myTransportableStateListenerMutex, MSGlobals::gNumThreads > 1);
1419 : #endif
1420 1012495 : for (TransportableStateListener* const listener : myTransportableStateListeners) {
1421 2808 : listener->transportableStateChanged(transportable, to, info);
1422 : }
1423 1009687 : }
1424 :
1425 :
1426 : bool
1427 19420 : MSNet::registerCollision(const SUMOTrafficObject* collider, const SUMOTrafficObject* victim, const std::string& collisionType, const MSLane* lane, double pos) {
1428 : auto it = myCollisions.find(collider->getID());
1429 19420 : if (it != myCollisions.end()) {
1430 12561 : for (Collision& old : it->second) {
1431 12442 : if (old.victim == victim->getID()) {
1432 : // collision from previous step continues
1433 11063 : old.continuationTime = myStep;
1434 : return false;
1435 : }
1436 : }
1437 : } else {
1438 : // maybe the roles have been reversed
1439 : auto it2 = myCollisions.find(victim->getID());
1440 8238 : if (it2 != myCollisions.end()) {
1441 2041 : for (Collision& old : it2->second) {
1442 1884 : if (old.victim == collider->getID()) {
1443 : // collision from previous step continues (keep the old roles)
1444 1717 : old.continuationTime = myStep;
1445 : return false;
1446 : }
1447 : }
1448 : }
1449 : }
1450 : Collision c;
1451 : c.victim = victim->getID();
1452 6640 : c.colliderType = collider->getVehicleType().getID();
1453 6640 : c.victimType = victim->getVehicleType().getID();
1454 6640 : c.colliderSpeed = collider->getSpeed();
1455 6640 : c.victimSpeed = victim->getSpeed();
1456 6640 : c.colliderFront = collider->getPosition();
1457 6640 : c.victimFront = victim->getPosition();
1458 6640 : c.colliderBack = collider->getPosition(-collider->getVehicleType().getLength());
1459 6640 : c.victimBack = victim->getPosition(-victim->getVehicleType().getLength());
1460 : c.type = collisionType;
1461 6640 : c.lane = lane;
1462 6640 : c.pos = pos;
1463 6640 : c.time = myStep;
1464 6640 : c.continuationTime = myStep;
1465 6640 : myCollisions[collider->getID()].push_back(c);
1466 : return true;
1467 6640 : }
1468 :
1469 :
1470 : void
1471 115156754 : MSNet::removeOutdatedCollisions() {
1472 115175637 : for (auto it = myCollisions.begin(); it != myCollisions.end();) {
1473 38573 : for (auto it2 = it->second.begin(); it2 != it->second.end();) {
1474 19690 : if (it2->continuationTime != myStep) {
1475 6627 : it2 = it->second.erase(it2);
1476 : } else {
1477 : it2++;
1478 : }
1479 : }
1480 18883 : if (it->second.size() == 0) {
1481 : it = myCollisions.erase(it);
1482 : } else {
1483 : it++;
1484 : }
1485 : }
1486 115156754 : }
1487 :
1488 :
1489 : bool
1490 83957 : MSNet::addStoppingPlace(SumoXMLTag category, MSStoppingPlace* stop) {
1491 83957 : if (category == SUMO_TAG_TRAIN_STOP) {
1492 14049 : category = SUMO_TAG_BUS_STOP;
1493 : }
1494 83957 : const bool isNew = myStoppingPlaces[category].add(stop->getID(), stop);
1495 83957 : if (isNew && stop->getMyName() != "") {
1496 15969 : myNamedStoppingPlaces[category][stop->getMyName()].push_back(stop);
1497 : }
1498 83957 : return isNew;
1499 : }
1500 :
1501 :
1502 : bool
1503 17 : MSNet::addTractionSubstation(MSTractionSubstation* substation) {
1504 17 : if (find(myTractionSubstations.begin(), myTractionSubstations.end(), substation) == myTractionSubstations.end()) {
1505 17 : myTractionSubstations.push_back(substation);
1506 17 : return true;
1507 : }
1508 : return false;
1509 : }
1510 :
1511 :
1512 : MSStoppingPlace*
1513 1602380 : MSNet::getStoppingPlace(const std::string& id, const SumoXMLTag category) const {
1514 : if (myStoppingPlaces.count(category) > 0) {
1515 : return myStoppingPlaces.find(category)->second.get(id);
1516 : }
1517 : return nullptr;
1518 : }
1519 :
1520 :
1521 : MSStoppingPlace*
1522 172580 : MSNet::getStoppingPlace(const std::string& id) const {
1523 855583 : 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})) {
1524 719493 : MSStoppingPlace* result = getStoppingPlace(id, category);
1525 719493 : if (result != nullptr) {
1526 : return result;
1527 : }
1528 172580 : }
1529 136090 : return nullptr;
1530 : }
1531 :
1532 :
1533 : std::string
1534 465942 : MSNet::getStoppingPlaceID(const MSLane* lane, const double pos, const SumoXMLTag category) const {
1535 : if (myStoppingPlaces.count(category) > 0) {
1536 955672 : for (const auto& it : myStoppingPlaces.find(category)->second) {
1537 875373 : MSStoppingPlace* stop = it.second;
1538 875373 : if (&stop->getLane() == lane && stop->getBeginLanePosition() - POSITION_EPS <= pos && stop->getEndLanePosition() + POSITION_EPS >= pos) {
1539 : return stop->getID();
1540 : }
1541 : }
1542 : }
1543 359997 : return "";
1544 : }
1545 :
1546 :
1547 : const std::vector<MSStoppingPlace*>&
1548 1590 : MSNet::getStoppingPlaceAlternatives(const std::string& name, SumoXMLTag category) const {
1549 1590 : if (category == SUMO_TAG_TRAIN_STOP) {
1550 : category = SUMO_TAG_BUS_STOP;
1551 : }
1552 : auto it = myNamedStoppingPlaces.find(category);
1553 1590 : if (it != myNamedStoppingPlaces.end()) {
1554 : auto it2 = it->second.find(name);
1555 1515 : if (it2 != it->second.end()) {
1556 1515 : return it2->second;
1557 : }
1558 : }
1559 : return myEmptyStoppingPlaceVector;
1560 : }
1561 :
1562 :
1563 : const NamedObjectCont<MSStoppingPlace*>&
1564 14009 : MSNet::getStoppingPlaces(SumoXMLTag category) const {
1565 : auto it = myStoppingPlaces.find(category);
1566 14009 : if (it != myStoppingPlaces.end()) {
1567 13724 : return it->second;
1568 : } else {
1569 : return myEmptyStoppingPlaceCont;
1570 : }
1571 : }
1572 :
1573 :
1574 : void
1575 106 : MSNet::writeChargingStationOutput() const {
1576 : if (myStoppingPlaces.count(SUMO_TAG_CHARGING_STATION) > 0) {
1577 204 : OutputDevice& output = OutputDevice::getDeviceByOption("chargingstations-output");
1578 586 : for (const auto& it : myStoppingPlaces.find(SUMO_TAG_CHARGING_STATION)->second) {
1579 484 : static_cast<MSChargingStation*>(it.second)->writeChargingStationOutput(output);
1580 : }
1581 : }
1582 106 : }
1583 :
1584 :
1585 : void
1586 40817 : MSNet::writeRailSignalBlocks() const {
1587 81634 : if (OptionsCont::getOptions().isSet("railsignal-block-output")) {
1588 1367 : OutputDevice& output = OutputDevice::getDeviceByOption("railsignal-block-output");
1589 5420 : for (auto tls : myLogics->getAllLogics()) {
1590 4053 : MSRailSignal* rs = dynamic_cast<MSRailSignal*>(tls);
1591 4053 : if (rs != nullptr) {
1592 4009 : rs->writeBlocks(output, false);
1593 : }
1594 1367 : }
1595 1367 : MSDriveWay::writeDepatureBlocks(output, false);
1596 : }
1597 81634 : if (OptionsCont::getOptions().isSet("railsignal-vehicle-output")) {
1598 185 : OutputDevice& output = OutputDevice::getDeviceByOption("railsignal-vehicle-output");
1599 599 : for (auto tls : myLogics->getAllLogics()) {
1600 414 : MSRailSignal* rs = dynamic_cast<MSRailSignal*>(tls);
1601 414 : if (rs != nullptr) {
1602 414 : rs->writeBlocks(output, true);
1603 : }
1604 185 : }
1605 185 : MSDriveWay::writeDepatureBlocks(output, true);
1606 : }
1607 40817 : }
1608 :
1609 :
1610 : void
1611 5 : MSNet::writeOverheadWireSegmentOutput() const {
1612 : if (myStoppingPlaces.count(SUMO_TAG_OVERHEAD_WIRE_SEGMENT) > 0) {
1613 10 : OutputDevice& output = OutputDevice::getDeviceByOption("overheadwiresegments-output");
1614 53 : for (const auto& it : myStoppingPlaces.find(SUMO_TAG_OVERHEAD_WIRE_SEGMENT)->second) {
1615 48 : static_cast<MSOverheadWire*>(it.second)->writeOverheadWireSegmentOutput(output);
1616 : }
1617 : }
1618 5 : }
1619 :
1620 :
1621 : void
1622 5 : MSNet::writeSubstationOutput() const {
1623 5 : if (myTractionSubstations.size() > 0) {
1624 5 : OutputDevice& output = OutputDevice::getDeviceByOption("substations-output");
1625 10 : output.setPrecision(OptionsCont::getOptions().getInt("substations-output.precision"));
1626 13 : for (auto& it : myTractionSubstations) {
1627 8 : it->writeTractionSubstationOutput(output);
1628 : }
1629 : }
1630 5 : }
1631 :
1632 :
1633 : MSTractionSubstation*
1634 19 : MSNet::findTractionSubstation(const std::string& substationId) {
1635 22 : for (std::vector<MSTractionSubstation*>::iterator it = myTractionSubstations.begin(); it != myTractionSubstations.end(); ++it) {
1636 22 : if ((*it)->getID() == substationId) {
1637 : return *it;
1638 : }
1639 : }
1640 : return nullptr;
1641 : }
1642 :
1643 :
1644 : MSVehicleRouter&
1645 127276 : MSNet::getRouterTT(int rngIndex, const Prohibitions& prohibited) const {
1646 127276 : if (MSGlobals::gNumSimThreads == 1) {
1647 108372 : rngIndex = 0;
1648 : }
1649 : if (myRouterTT.count(rngIndex) == 0) {
1650 1472 : const std::string routingAlgorithm = OptionsCont::getOptions().getString("routing-algorithm");
1651 1472 : if (routingAlgorithm == "dijkstra") {
1652 1374 : myRouterTT[rngIndex] = new DijkstraRouter<MSEdge, SUMOVehicle>(MSEdge::getAllEdges(), true, &MSNet::getTravelTime, nullptr, false, nullptr, true);
1653 : } else {
1654 98 : if (routingAlgorithm != "astar") {
1655 0 : WRITE_WARNINGF(TL("TraCI and Triggers cannot use routing algorithm '%'. using 'astar' instead."), routingAlgorithm);
1656 : }
1657 98 : myRouterTT[rngIndex] = new AStarRouter<MSEdge, SUMOVehicle, MSMapMatcher>(MSEdge::getAllEdges(), true, &MSNet::getTravelTime, nullptr, true);
1658 : }
1659 : }
1660 127276 : myRouterTT[rngIndex]->prohibit(prohibited);
1661 127276 : return *myRouterTT[rngIndex];
1662 : }
1663 :
1664 :
1665 : MSVehicleRouter&
1666 11 : MSNet::getRouterEffort(int rngIndex, const Prohibitions& prohibited) const {
1667 11 : if (MSGlobals::gNumSimThreads == 1) {
1668 11 : rngIndex = 0;
1669 : }
1670 : if (myRouterEffort.count(rngIndex) == 0) {
1671 11 : myRouterEffort[rngIndex] = new DijkstraRouter<MSEdge, SUMOVehicle>(MSEdge::getAllEdges(), true, &MSNet::getEffort, &MSNet::getTravelTime, false, nullptr, true);
1672 : }
1673 11 : myRouterEffort[rngIndex]->prohibit(prohibited);
1674 11 : return *myRouterEffort[rngIndex];
1675 : }
1676 :
1677 :
1678 : MSPedestrianRouter&
1679 816099 : MSNet::getPedestrianRouter(int rngIndex, const Prohibitions& prohibited) const {
1680 816099 : if (MSGlobals::gNumSimThreads == 1) {
1681 727216 : rngIndex = 0;
1682 : }
1683 : if (myPedestrianRouter.count(rngIndex) == 0) {
1684 2826 : myPedestrianRouter[rngIndex] = new MSPedestrianRouter();
1685 : }
1686 816099 : myPedestrianRouter[rngIndex]->prohibit(prohibited);
1687 816099 : return *myPedestrianRouter[rngIndex];
1688 : }
1689 :
1690 :
1691 : MSTransportableRouter&
1692 164543 : MSNet::getIntermodalRouter(int rngIndex, const int routingMode, const Prohibitions& prohibited) const {
1693 164543 : if (MSGlobals::gNumSimThreads == 1) {
1694 : rngIndex = 0;
1695 : }
1696 164543 : const OptionsCont& oc = OptionsCont::getOptions();
1697 164543 : const int key = rngIndex * oc.getInt("thread-rngs") + routingMode;
1698 : if (myIntermodalRouter.count(key) == 0) {
1699 3892 : const int carWalk = SUMOVehicleParserHelper::parseCarWalkTransfer(oc, MSDevice_Taxi::hasFleet() || myInserter->hasTaxiFlow());
1700 3712 : const std::string routingAlgorithm = OptionsCont::getOptions().getString("routing-algorithm");
1701 3712 : const double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
1702 3712 : if (routingMode == libsumo::ROUTING_MODE_COMBINED) {
1703 0 : myIntermodalRouter[key] = new MSTransportableRouter(MSNet::adaptIntermodalRouter, carWalk, taxiWait, routingAlgorithm, routingMode, new FareModul());
1704 : } else {
1705 3712 : myIntermodalRouter[key] = new MSTransportableRouter(MSNet::adaptIntermodalRouter, carWalk, taxiWait, routingAlgorithm, routingMode);
1706 : }
1707 : }
1708 164543 : myIntermodalRouter[key]->prohibit(prohibited);
1709 164543 : return *myIntermodalRouter[key];
1710 : }
1711 :
1712 :
1713 : void
1714 42425 : MSNet::resetIntermodalRouter() const {
1715 46136 : for (auto& router : myIntermodalRouter) {
1716 3711 : delete router.second;
1717 : }
1718 : myIntermodalRouter.clear();
1719 42425 : }
1720 :
1721 :
1722 : void
1723 4847 : MSNet::adaptIntermodalRouter(MSTransportableRouter& router) {
1724 9694 : double taxiWait = STEPS2TIME(string2time(OptionsCont::getOptions().getString("persontrip.taxi.waiting-time")));
1725 : // add access to all parking areas
1726 : EffortCalculator* const external = router.getExternalEffort();
1727 14536 : for (const auto& stopType : myInstance->myStoppingPlaces) {
1728 : // add access to all stopping places
1729 9689 : const SumoXMLTag element = stopType.first;
1730 35748 : for (const auto& i : stopType.second) {
1731 26059 : const MSEdge* const edge = &i.second->getLane().getEdge();
1732 26059 : router.getNetwork()->addAccess(i.first, edge, i.second->getBeginLanePosition(), i.second->getEndLanePosition(),
1733 : 0., element, false, taxiWait);
1734 26059 : if (element == SUMO_TAG_BUS_STOP) {
1735 : // add access to all public transport stops
1736 12550 : for (const auto& a : i.second->getAllAccessPos()) {
1737 1123 : router.getNetwork()->addAccess(i.first, &a.lane->getEdge(), a.startPos, a.endPos, a.length, element, true, taxiWait);
1738 : }
1739 11427 : if (external != nullptr) {
1740 0 : external->addStop(router.getNetwork()->getStopEdge(i.first)->getNumericalID(), *i.second);
1741 : }
1742 : }
1743 : }
1744 : }
1745 4847 : myInstance->getInsertionControl().adaptIntermodalRouter(router);
1746 4847 : myInstance->getVehicleControl().adaptIntermodalRouter(router);
1747 : // add access to transfer from walking to taxi-use
1748 4847 : if ((router.getCarWalkTransfer() & ModeChangeOptions::TAXI_PICKUP_ANYWHERE) != 0) {
1749 61243 : for (MSEdge* edge : myInstance->getEdgeControl().getEdges()) {
1750 61013 : if ((edge->getPermissions() & SVC_PEDESTRIAN) != 0 && (edge->getPermissions() & SVC_TAXI) != 0) {
1751 20301 : router.getNetwork()->addCarAccess(edge, SVC_TAXI, taxiWait);
1752 : }
1753 : }
1754 : }
1755 4847 : }
1756 :
1757 :
1758 : bool
1759 42464 : MSNet::checkElevation() {
1760 42464 : const MSEdgeVector& edges = myEdges->getEdges();
1761 1826616 : for (MSEdgeVector::const_iterator e = edges.begin(); e != edges.end(); ++e) {
1762 3929866 : for (std::vector<MSLane*>::const_iterator i = (*e)->getLanes().begin(); i != (*e)->getLanes().end(); ++i) {
1763 2145714 : if ((*i)->getShape().hasElevation()) {
1764 : return true;
1765 : }
1766 : }
1767 : }
1768 : return false;
1769 : }
1770 :
1771 :
1772 : bool
1773 42464 : MSNet::checkWalkingarea() {
1774 1256709 : for (const MSEdge* e : myEdges->getEdges()) {
1775 1224828 : if (e->getFunction() == SumoXMLEdgeFunc::WALKINGAREA) {
1776 : return true;
1777 : }
1778 : }
1779 : return false;
1780 : }
1781 :
1782 :
1783 : bool
1784 42464 : MSNet::checkBidiEdges() {
1785 1763535 : for (const MSEdge* e : myEdges->getEdges()) {
1786 1722327 : if (e->getBidiEdge() != nullptr) {
1787 : return true;
1788 : }
1789 : }
1790 : return false;
1791 : }
1792 :
1793 : bool
1794 303 : MSNet::warnOnce(const std::string& typeAndID) {
1795 303 : if (myWarnedOnce.find(typeAndID) == myWarnedOnce.end()) {
1796 303 : myWarnedOnce[typeAndID] = true;
1797 303 : return true;
1798 : }
1799 : return false;
1800 : }
1801 :
1802 :
1803 : MSMapMatcher*
1804 35 : MSNet::getMapMatcher() const {
1805 35 : auto loader = myRouteLoaders->getFirstLoader();
1806 35 : if (loader != nullptr) {
1807 35 : return dynamic_cast<MSMapMatcher*>(loader->getRouteHandler());
1808 : } else {
1809 : return nullptr;
1810 : }
1811 : }
1812 :
1813 : void
1814 0 : MSNet::quickReload() {
1815 0 : const OptionsCont& oc = OptionsCont::getOptions();
1816 0 : clearState(string2time(oc.getString("begin")), true);
1817 0 : NLBuilder::initRandomness();
1818 : // load traffic from additional files
1819 0 : for (std::string file : oc.getStringVector("additional-files")) {
1820 : // ignore failure on parsing calibrator flow
1821 0 : MSRouteHandler rh(file, true);
1822 0 : const long before = PROGRESS_BEGIN_TIME_MESSAGE("Loading traffic from '" + file + "'");
1823 0 : if (!XMLSubSys::runParser(rh, file, false)) {
1824 0 : throw ProcessError(TLF("Loading of % failed.", file));
1825 : }
1826 0 : PROGRESS_TIME_MESSAGE(before);
1827 0 : }
1828 0 : delete myRouteLoaders;
1829 0 : myRouteLoaders = NLBuilder::buildRouteLoaderControl(OptionsCont::getOptions());
1830 0 : updateGUI();
1831 0 : }
1832 :
1833 :
1834 : SUMOTime
1835 172 : MSNet::loadState(const std::string& fileName, const bool catchExceptions) {
1836 : // load time only
1837 172 : const SUMOTime newTime = MSStateHandler::MSStateTimeHandler::getTime(fileName);
1838 : // clean up state
1839 162 : clearState(newTime);
1840 : // load state
1841 162 : MSStateHandler h(fileName, 0);
1842 162 : XMLSubSys::runParser(h, fileName, false, false, false, catchExceptions);
1843 158 : if (MsgHandler::getErrorInstance()->wasInformed()) {
1844 0 : throw ProcessError(TLF("Loading state from '%' failed.", fileName));
1845 : }
1846 : // reset route loaders
1847 158 : delete myRouteLoaders;
1848 158 : myRouteLoaders = NLBuilder::buildRouteLoaderControl(OptionsCont::getOptions());
1849 : // prevent loading errors on rewound route file
1850 158 : MSGlobals::gStateLoaded = true;
1851 :
1852 158 : updateGUI();
1853 158 : return newTime;
1854 162 : }
1855 :
1856 :
1857 : /****************************************************************************/
|