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