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