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