Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2017-2024 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 Simulation.cpp
15 : /// @author Laura Bieker-Walz
16 : /// @author Robert Hilbrich
17 : /// @author Mirko Barthauer
18 : /// @date 15.09.2017
19 : ///
20 : // C++ TraCI client API implementation
21 : /****************************************************************************/
22 : #include <config.h>
23 : #ifdef HAVE_VERSION_H
24 : #include <version.h>
25 : #endif
26 : #include <utils/options/OptionsCont.h>
27 : #include <utils/common/MsgHandler.h>
28 : #include <utils/common/StdDefs.h>
29 : #include <utils/common/StringTokenizer.h>
30 : #include <utils/common/StringUtils.h>
31 : #include <utils/common/SystemFrame.h>
32 : #include <utils/geom/GeoConvHelper.h>
33 : #include <utils/options/OptionsIO.h>
34 : #include <utils/router/IntermodalRouter.h>
35 : #include <utils/router/PedestrianRouter.h>
36 : #include <utils/xml/XMLSubSys.h>
37 : #include <microsim/MSNet.h>
38 : #include <microsim/MSEdgeControl.h>
39 : #include <microsim/MSInsertionControl.h>
40 : #include <microsim/MSEdge.h>
41 : #include <microsim/MSLane.h>
42 : #include <microsim/MSVehicle.h>
43 : #include <microsim/MSVehicleControl.h>
44 : #include <microsim/MSVehicleTransfer.h>
45 : #include <microsim/transportables/MSTransportableControl.h>
46 : #include <microsim/MSStateHandler.h>
47 : #include <microsim/MSStoppingPlace.h>
48 : #include <microsim/MSParkingArea.h>
49 : #include <microsim/devices/MSRoutingEngine.h>
50 : #include <microsim/trigger/MSChargingStation.h>
51 : #include <microsim/trigger/MSOverheadWire.h>
52 : #include <microsim/devices/MSDevice_Tripinfo.h>
53 : #include <mesosim/MELoop.h>
54 : #include <mesosim/MESegment.h>
55 : #include <netload/NLBuilder.h>
56 : #include <libsumo/Helper.h>
57 : #include <libsumo/TraCIConstants.h>
58 : #ifdef HAVE_LIBSUMOGUI
59 : #include "GUI.h"
60 : #endif
61 : #include "Simulation.h"
62 : #include <libsumo/TraCIDefs.h>
63 :
64 :
65 : namespace libsumo {
66 : // ===========================================================================
67 : // static member initializations
68 : // ===========================================================================
69 : SubscriptionResults Simulation::mySubscriptionResults;
70 : ContextSubscriptionResults Simulation::myContextSubscriptionResults;
71 :
72 :
73 : // ===========================================================================
74 : // static member definitions
75 : // ===========================================================================
76 : std::pair<int, std::string>
77 1003 : Simulation::start(const std::vector<std::string>& cmd, int /* port */, int /* numRetries */, const std::string& /* label */, const bool /* verbose */,
78 : const std::string& /* traceFile */, bool /* traceGetters */, void* /* _stdout */) {
79 : #ifdef HAVE_LIBSUMOGUI
80 1003 : if (GUI::start(cmd)) {
81 465 : return getVersion();
82 : }
83 : #endif
84 537 : load(std::vector<std::string>(cmd.begin() + 1, cmd.end()));
85 537 : return getVersion();
86 : }
87 :
88 :
89 : void
90 553 : Simulation::load(const std::vector<std::string>& args) {
91 : #ifdef HAVE_LIBSUMOGUI
92 553 : if (GUI::load(args)) {
93 : return;
94 : }
95 : #endif
96 551 : close("Libsumo issued load command.");
97 : try {
98 1102 : OptionsCont::getOptions().setApplicationName("libsumo", "Eclipse SUMO libsumo Version " VERSION_STRING);
99 551 : gSimulation = true;
100 551 : XMLSubSys::init();
101 551 : OptionsIO::setArgs(args);
102 551 : if (NLBuilder::init(true) != nullptr) {
103 1094 : const SUMOTime begin = string2time(OptionsCont::getOptions().getString("begin"));
104 547 : MSNet::getInstance()->setCurrentTimeStep(begin); // needed for state loading
105 1094 : WRITE_MESSAGEF(TL("Simulation version % started via libsumo with time: %."), VERSION_STRING, time2string(begin));
106 : }
107 0 : } catch (ProcessError& e) {
108 0 : throw TraCIException(e.what());
109 0 : }
110 0 : }
111 :
112 :
113 : bool
114 2 : Simulation::hasGUI() {
115 : #ifdef HAVE_LIBSUMOGUI
116 2 : return GUI::hasInstance();
117 : #else
118 0 : return false;
119 : #endif
120 : }
121 :
122 :
123 : bool
124 8 : Simulation::isLoaded() {
125 8 : return MSNet::hasInstance();
126 : }
127 :
128 :
129 : void
130 156113 : Simulation::step(const double time) {
131 156113 : Helper::clearStateChanges();
132 156113 : const SUMOTime t = TIME2STEPS(time);
133 : #ifdef HAVE_LIBSUMOGUI
134 156113 : if (!GUI::step(t)) {
135 : #endif
136 79320 : if (t == 0) {
137 78735 : MSNet::getInstance()->simulationStep();
138 : } else {
139 2668 : while (MSNet::getInstance()->getCurrentTimeStep() < t) {
140 2083 : MSNet::getInstance()->simulationStep();
141 : }
142 : }
143 : #ifdef HAVE_LIBSUMOGUI
144 : }
145 : #endif
146 156113 : Helper::handleSubscriptions(t);
147 156113 : }
148 :
149 :
150 : void
151 4 : Simulation::executeMove() {
152 4 : MSNet::getInstance()->simulationStep(true);
153 4 : }
154 :
155 :
156 : void
157 1549 : Simulation::close(const std::string& reason) {
158 1549 : Helper::clearSubscriptions();
159 0 : if (
160 : #ifdef HAVE_LIBSUMOGUI
161 1549 : !GUI::close(reason) &&
162 : #endif
163 : MSNet::hasInstance()) {
164 546 : MSNet::getInstance()->closeSimulation(0, reason);
165 546 : delete MSNet::getInstance();
166 546 : SystemFrame::close();
167 : }
168 1548 : }
169 :
170 :
171 : void
172 4 : Simulation::subscribe(const std::vector<int>& varIDs, double begin, double end, const libsumo::TraCIResults& params) {
173 4 : libsumo::Helper::subscribe(CMD_SUBSCRIBE_SIM_VARIABLE, "", varIDs, begin, end, params);
174 4 : }
175 :
176 :
177 : const TraCIResults
178 58 : Simulation::getSubscriptionResults() {
179 116 : return mySubscriptionResults[""];
180 : }
181 :
182 :
183 308 : LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(Simulation, SIM)
184 :
185 :
186 : std::pair<int, std::string>
187 1004 : Simulation::getVersion() {
188 1004 : return std::make_pair(libsumo::TRACI_VERSION, "SUMO " VERSION_STRING);
189 : }
190 :
191 :
192 : std::string
193 7 : Simulation::getOption(const std::string& option) {
194 7 : OptionsCont& oc = OptionsCont::getOptions();
195 7 : if (!oc.exists(option)) {
196 0 : throw TraCIException("The option " + option + " is unknown.");
197 : }
198 7 : return oc.getValueString(option);
199 : }
200 :
201 :
202 : int
203 6 : Simulation::getCurrentTime() {
204 6 : return (int)MSNet::getInstance()->getCurrentTimeStep();
205 : }
206 :
207 :
208 : double
209 362431 : Simulation::getTime() {
210 362431 : return SIMTIME;
211 : }
212 :
213 : double
214 8 : Simulation::getEndTime() {
215 8 : return STEPS2TIME(string2time(OptionsCont::getOptions().getString("end")));
216 : }
217 :
218 :
219 : int
220 8 : Simulation::getLoadedNumber() {
221 8 : return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::BUILT).size();
222 : }
223 :
224 :
225 : std::vector<std::string>
226 48 : Simulation::getLoadedIDList() {
227 48 : return Helper::getVehicleStateChanges(MSNet::VehicleState::BUILT);
228 : }
229 :
230 :
231 : int
232 1256 : Simulation::getDepartedNumber() {
233 1256 : return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::DEPARTED).size();
234 : }
235 :
236 :
237 : std::vector<std::string>
238 6060 : Simulation::getDepartedIDList() {
239 6060 : return Helper::getVehicleStateChanges(MSNet::VehicleState::DEPARTED);
240 : }
241 :
242 :
243 : int
244 684 : Simulation::getArrivedNumber() {
245 684 : return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::ARRIVED).size();
246 : }
247 :
248 :
249 : std::vector<std::string>
250 6012 : Simulation::getArrivedIDList() {
251 6012 : return Helper::getVehicleStateChanges(MSNet::VehicleState::ARRIVED);
252 : }
253 :
254 :
255 : int
256 8 : Simulation::getParkingStartingVehiclesNumber() {
257 8 : return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::STARTING_PARKING).size();
258 : }
259 :
260 :
261 : std::vector<std::string>
262 8 : Simulation::getParkingStartingVehiclesIDList() {
263 8 : return Helper::getVehicleStateChanges(MSNet::VehicleState::STARTING_PARKING);
264 : }
265 :
266 :
267 : int
268 8 : Simulation::getParkingEndingVehiclesNumber() {
269 8 : return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::ENDING_PARKING).size();
270 : }
271 :
272 :
273 : std::vector<std::string>
274 8 : Simulation::getParkingEndingVehiclesIDList() {
275 8 : return Helper::getVehicleStateChanges(MSNet::VehicleState::ENDING_PARKING);
276 : }
277 :
278 :
279 : int
280 8 : Simulation::getStopStartingVehiclesNumber() {
281 8 : return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::STARTING_STOP).size();
282 : }
283 :
284 :
285 : std::vector<std::string>
286 8 : Simulation::getStopStartingVehiclesIDList() {
287 8 : return Helper::getVehicleStateChanges(MSNet::VehicleState::STARTING_STOP);
288 : }
289 :
290 :
291 : int
292 8 : Simulation::getStopEndingVehiclesNumber() {
293 8 : return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::ENDING_STOP).size();
294 : }
295 :
296 :
297 : std::vector<std::string>
298 8 : Simulation::getStopEndingVehiclesIDList() {
299 8 : return Helper::getVehicleStateChanges(MSNet::VehicleState::ENDING_STOP);
300 : }
301 :
302 :
303 : int
304 32 : Simulation::getCollidingVehiclesNumber() {
305 32 : return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::COLLISION).size();
306 : }
307 :
308 :
309 : std::vector<std::string>
310 8 : Simulation::getCollidingVehiclesIDList() {
311 8 : return Helper::getVehicleStateChanges(MSNet::VehicleState::COLLISION);
312 : }
313 :
314 :
315 : int
316 32 : Simulation::getEmergencyStoppingVehiclesNumber() {
317 32 : return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::EMERGENCYSTOP).size();
318 : }
319 :
320 :
321 : std::vector<std::string>
322 8 : Simulation::getEmergencyStoppingVehiclesIDList() {
323 8 : return Helper::getVehicleStateChanges(MSNet::VehicleState::EMERGENCYSTOP);
324 : }
325 :
326 :
327 : int
328 8 : Simulation::getStartingTeleportNumber() {
329 8 : return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::STARTING_TELEPORT).size();
330 : }
331 :
332 :
333 : std::vector<std::string>
334 8 : Simulation::getStartingTeleportIDList() {
335 8 : return Helper::getVehicleStateChanges(MSNet::VehicleState::STARTING_TELEPORT);
336 : }
337 :
338 :
339 : int
340 8 : Simulation::getEndingTeleportNumber() {
341 8 : return (int)Helper::getVehicleStateChanges(MSNet::VehicleState::ENDING_TELEPORT).size();
342 : }
343 :
344 :
345 : std::vector<std::string>
346 8 : Simulation::getEndingTeleportIDList() {
347 8 : return Helper::getVehicleStateChanges(MSNet::VehicleState::ENDING_TELEPORT);
348 : }
349 :
350 : int
351 6 : Simulation::getDepartedPersonNumber() {
352 6 : return (int)Helper::getTransportableStateChanges(MSNet::TransportableState::PERSON_DEPARTED).size();
353 : }
354 :
355 :
356 : std::vector<std::string>
357 6 : Simulation::getDepartedPersonIDList() {
358 6 : return Helper::getTransportableStateChanges(MSNet::TransportableState::PERSON_DEPARTED);
359 : }
360 :
361 :
362 : int
363 6 : Simulation::getArrivedPersonNumber() {
364 6 : return (int)Helper::getTransportableStateChanges(MSNet::TransportableState::PERSON_ARRIVED).size();
365 : }
366 :
367 :
368 : std::vector<std::string>
369 6 : Simulation::getArrivedPersonIDList() {
370 6 : return Helper::getTransportableStateChanges(MSNet::TransportableState::PERSON_ARRIVED);
371 : }
372 :
373 : std::vector<std::string>
374 6 : Simulation::getBusStopIDList() {
375 : std::vector<std::string> result;
376 12 : for (const auto& pair : MSNet::getInstance()->getStoppingPlaces(SUMO_TAG_BUS_STOP)) {
377 6 : result.push_back(pair.first);
378 : }
379 6 : return result;
380 0 : }
381 :
382 : int
383 13 : Simulation::getBusStopWaiting(const std::string& stopID) {
384 13 : MSStoppingPlace* s = MSNet::getInstance()->getStoppingPlace(stopID, SUMO_TAG_BUS_STOP);
385 13 : if (s == nullptr) {
386 12 : throw TraCIException("Unknown bus stop '" + stopID + "'.");
387 : }
388 7 : return s->getTransportableNumber();
389 : }
390 :
391 : std::vector<std::string>
392 187 : Simulation::getBusStopWaitingIDList(const std::string& stopID) {
393 187 : MSStoppingPlace* s = MSNet::getInstance()->getStoppingPlace(stopID, SUMO_TAG_BUS_STOP);
394 187 : if (s == nullptr) {
395 0 : throw TraCIException("Unknown bus stop '" + stopID + "'.");
396 : }
397 : std::vector<std::string> result;
398 254 : for (const MSTransportable* t : s->getTransportables()) {
399 67 : result.push_back(t->getID());
400 : }
401 187 : return result;
402 0 : }
403 :
404 :
405 : std::vector<std::string>
406 36 : Simulation::getPendingVehicles() {
407 : std::vector<std::string> result;
408 42 : for (const SUMOVehicle* veh : MSNet::getInstance()->getInsertionControl().getPendingVehicles()) {
409 6 : result.push_back(veh->getID());
410 : }
411 36 : return result;
412 0 : }
413 :
414 :
415 : std::vector<libsumo::TraCICollision>
416 408 : Simulation::getCollisions() {
417 : std::vector<libsumo::TraCICollision> result;
418 438 : for (auto item : MSNet::getInstance()->getCollisions()) {
419 60 : for (const MSNet::Collision& c : item.second) {
420 : libsumo::TraCICollision c2;
421 : c2.collider = item.first;
422 30 : c2.victim = c.victim;
423 30 : c2.colliderType = c.colliderType;
424 30 : c2.victimType = c.victimType;
425 30 : c2.colliderSpeed = c.colliderSpeed;
426 30 : c2.victimSpeed = c.victimSpeed;
427 30 : c2.type = c.type;
428 30 : c2.lane = c.lane->getID();
429 30 : c2.pos = c.pos;
430 30 : result.push_back(c2);
431 30 : }
432 30 : }
433 408 : return result;
434 0 : }
435 :
436 : double
437 6 : Simulation::getScale() {
438 6 : return MSNet::getInstance()->getVehicleControl().getScale();
439 : }
440 :
441 : double
442 179 : Simulation::getDeltaT() {
443 179 : return TS;
444 : }
445 :
446 :
447 : TraCIPositionVector
448 6 : Simulation::getNetBoundary() {
449 6 : Boundary b = GeoConvHelper::getFinal().getConvBoundary();
450 : TraCIPositionVector tb;
451 6 : TraCIPosition minV;
452 6 : TraCIPosition maxV;
453 6 : minV.x = b.xmin();
454 6 : maxV.x = b.xmax();
455 6 : minV.y = b.ymin();
456 6 : maxV.y = b.ymax();
457 6 : minV.z = b.zmin();
458 6 : maxV.z = b.zmax();
459 6 : tb.value.push_back(minV);
460 6 : tb.value.push_back(maxV);
461 6 : return tb;
462 6 : }
463 :
464 :
465 : int
466 6577018 : Simulation::getMinExpectedNumber() {
467 6577018 : MSNet* net = MSNet::getInstance();
468 : return (net->getVehicleControl().getActiveVehicleCount()
469 6577017 : + net->getInsertionControl().getPendingFlowCount()
470 6577017 : + (net->hasPersons() ? net->getPersonControl().getActiveCount() : 0)
471 6577017 : + (net->hasContainers() ? net->getContainerControl().getActiveCount() : 0));
472 : }
473 :
474 :
475 : TraCIPosition
476 87 : Simulation::convert2D(const std::string& edgeID, double pos, int laneIndex, bool toGeo) {
477 87 : Position result = Helper::getLaneChecking(edgeID, laneIndex, pos)->geometryPositionAtOffset(pos);
478 87 : if (toGeo) {
479 2 : GeoConvHelper::getFinal().cartesian2geo(result);
480 : }
481 : result.setz(0.);
482 87 : return Helper::makeTraCIPosition(result);
483 : }
484 :
485 :
486 : TraCIPosition
487 4 : Simulation::convert3D(const std::string& edgeID, double pos, int laneIndex, bool toGeo) {
488 4 : Position result = Helper::getLaneChecking(edgeID, laneIndex, pos)->geometryPositionAtOffset(pos);
489 4 : if (toGeo) {
490 2 : GeoConvHelper::getFinal().cartesian2geo(result);
491 : }
492 4 : return Helper::makeTraCIPosition(result, true);
493 : }
494 :
495 :
496 : TraCIRoadPosition
497 50 : Simulation::convertRoad(double x, double y, bool isGeo, const std::string& vClass) {
498 : Position pos(x, y);
499 50 : if (isGeo) {
500 6 : GeoConvHelper::getFinal().x2cartesian_const(pos);
501 : }
502 50 : if (!SumoVehicleClassStrings.hasString(vClass)) {
503 0 : throw TraCIException("Unknown vehicle class '" + vClass + "'.");
504 : }
505 50 : const SUMOVehicleClass vc = SumoVehicleClassStrings.get(vClass);
506 50 : std::pair<MSLane*, double> roadPos = libsumo::Helper::convertCartesianToRoadMap(pos, vc);
507 50 : if (roadPos.first == nullptr) {
508 0 : throw TraCIException("Cannot convert position to road.");
509 : }
510 : TraCIRoadPosition result;
511 : result.edgeID = roadPos.first->getEdge().getID();
512 50 : result.laneIndex = roadPos.first->getIndex();
513 50 : result.pos = roadPos.second;
514 50 : return result;
515 : }
516 :
517 :
518 : TraCIPosition
519 10 : Simulation::convertGeo(double x, double y, bool fromGeo) {
520 : Position pos(x, y);
521 10 : if (fromGeo) {
522 2 : GeoConvHelper::getFinal().x2cartesian_const(pos);
523 : } else {
524 8 : GeoConvHelper::getFinal().cartesian2geo(pos);
525 : }
526 10 : return Helper::makeTraCIPosition(pos);
527 : }
528 :
529 :
530 : double
531 40 : Simulation::getDistance2D(double x1, double y1, double x2, double y2, bool isGeo, bool isDriving) {
532 : Position pos1(x1, y1);
533 : Position pos2(x2, y2);
534 40 : if (isGeo) {
535 2 : GeoConvHelper::getFinal().x2cartesian_const(pos1);
536 2 : GeoConvHelper::getFinal().x2cartesian_const(pos2);
537 : }
538 40 : if (isDriving) {
539 36 : std::pair<const MSLane*, double> roadPos1 = libsumo::Helper::convertCartesianToRoadMap(pos1, SVC_IGNORING);
540 36 : std::pair<const MSLane*, double> roadPos2 = libsumo::Helper::convertCartesianToRoadMap(pos2, SVC_IGNORING);
541 36 : return Helper::getDrivingDistance(roadPos1, roadPos2);
542 : } else {
543 4 : return pos1.distanceTo(pos2);
544 : }
545 : }
546 :
547 :
548 : double
549 54 : Simulation::getDistanceRoad(const std::string& edgeID1, double pos1, const std::string& edgeID2, double pos2, bool isDriving) {
550 54 : std::pair<const MSLane*, double> roadPos1 = std::make_pair(libsumo::Helper::getLaneChecking(edgeID1, 0, pos1), pos1);
551 54 : std::pair<const MSLane*, double> roadPos2 = std::make_pair(libsumo::Helper::getLaneChecking(edgeID2, 0, pos2), pos2);
552 54 : if (isDriving) {
553 18 : return Helper::getDrivingDistance(roadPos1, roadPos2);
554 : } else {
555 36 : const Position p1 = roadPos1.first->geometryPositionAtOffset(roadPos1.second);
556 36 : const Position p2 = roadPos2.first->geometryPositionAtOffset(roadPos2.second);
557 36 : return p1.distanceTo(p2);
558 : }
559 : }
560 :
561 :
562 : TraCIStage
563 11845 : Simulation::findRoute(const std::string& from, const std::string& to, const std::string& typeID, const double depart, const int routingMode) {
564 23690 : TraCIStage result(STAGE_DRIVING);
565 11845 : const MSEdge* const fromEdge = MSEdge::dictionary(from);
566 11845 : if (fromEdge == nullptr) {
567 12 : throw TraCIException("Unknown from edge '" + from + "'.");
568 : }
569 11839 : const MSEdge* const toEdge = MSEdge::dictionary(to);
570 11839 : if (toEdge == nullptr) {
571 0 : throw TraCIException("Unknown to edge '" + to + "'.");
572 : }
573 : MSBaseVehicle* vehicle = nullptr;
574 35504 : MSVehicleType* type = MSNet::getInstance()->getVehicleControl().getVType(typeID == "" ? DEFAULT_VTYPE_ID : typeID);
575 11839 : if (type == nullptr) {
576 0 : throw TraCIException("The vehicle type '" + typeID + "' is not known.");
577 : }
578 11839 : SUMOVehicleParameter* pars = new SUMOVehicleParameter();
579 11839 : pars->id = "simulation.findRoute";
580 : try {
581 35517 : ConstMSRoutePtr const routeDummy = std::make_shared<MSRoute>("", ConstMSEdgeVector({ fromEdge }), false, nullptr, std::vector<SUMOVehicleParameter::Stop>());
582 23684 : vehicle = dynamic_cast<MSBaseVehicle*>(MSNet::getInstance()->getVehicleControl().buildVehicle(pars, routeDummy, type, false));
583 : std::string msg;
584 11839 : if (!vehicle->hasValidRouteStart(msg)) {
585 6 : MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
586 12 : throw TraCIException("Invalid departure edge for vehicle type '" + type->getID() + "' (" + msg + ")");
587 : }
588 : // we need to fix the speed factor here for deterministic results
589 11833 : vehicle->setChosenSpeedFactor(type->getSpeedFactor().getParameter()[0]);
590 : vehicle->setRoutingMode(routingMode);
591 6 : } catch (ProcessError& e) {
592 0 : throw TraCIException("Invalid departure edge for vehicle type '" + type->getID() + "' (" + e.what() + ")");
593 0 : }
594 : ConstMSEdgeVector edges;
595 11833 : const SUMOTime dep = depart < 0 ? MSNet::getInstance()->getCurrentTimeStep() : TIME2STEPS(depart);
596 23660 : SUMOAbstractRouter<MSEdge, SUMOVehicle>& router = routingMode == ROUTING_MODE_AGGREGATED ? MSRoutingEngine::getRouterTT(0, vehicle->getVClass()) : MSNet::getInstance()->getRouterTT(0);
597 11833 : router.compute(fromEdge, toEdge, vehicle, dep, edges);
598 62254 : for (const MSEdge* e : edges) {
599 50421 : result.edges.push_back(e->getID());
600 : }
601 11833 : result.travelTime = result.cost = router.recomputeCosts(edges, vehicle, dep, &result.length);
602 : if (vehicle != nullptr) {
603 11833 : MSNet::getInstance()->getVehicleControl().deleteVehicle(vehicle, true);
604 : }
605 11833 : return result;
606 12 : }
607 :
608 :
609 : std::vector<TraCIStage>
610 391 : Simulation::findIntermodalRoute(const std::string& from, const std::string& to,
611 : const std::string& modes, double depart, const int routingMode, double speed, double walkFactor,
612 : double departPos, double arrivalPos, const double departPosLat,
613 : const std::string& pType, const std::string& vType, const std::string& destStop) {
614 : UNUSED_PARAMETER(departPosLat);
615 : std::vector<TraCIStage> result;
616 391 : const MSEdge* const fromEdge = MSEdge::dictionary(from);
617 391 : if (fromEdge == nullptr) {
618 12 : throw TraCIException("Unknown from edge '" + from + "'.");
619 : }
620 385 : const MSEdge* const toEdge = MSEdge::dictionary(to);
621 385 : if (toEdge == nullptr) {
622 0 : throw TraCIException("Unknown to edge '" + to + "'.");
623 : }
624 385 : MSVehicleControl& vehControl = MSNet::getInstance()->getVehicleControl();
625 : SVCPermissions modeSet = 0;
626 : std::vector<SUMOVehicleParameter*> pars;
627 385 : if (vType != "") {
628 372 : pars.push_back(new SUMOVehicleParameter());
629 186 : pars.back()->vtypeid = vType;
630 186 : pars.back()->id = vType;
631 : modeSet |= SVC_PASSENGER;
632 : }
633 1223 : for (StringTokenizer st(modes); st.hasNext();) {
634 453 : const std::string mode = st.next();
635 453 : if (mode == toString(PersonMode::CAR)) {
636 174 : pars.push_back(new SUMOVehicleParameter());
637 87 : pars.back()->vtypeid = DEFAULT_VTYPE_ID;
638 87 : pars.back()->id = mode;
639 87 : modeSet |= SVC_PASSENGER;
640 366 : } else if (mode == toString(PersonMode::BICYCLE)) {
641 198 : pars.push_back(new SUMOVehicleParameter());
642 99 : pars.back()->vtypeid = DEFAULT_BIKETYPE_ID;
643 99 : pars.back()->id = mode;
644 99 : modeSet |= SVC_BICYCLE;
645 267 : } else if (mode == toString(PersonMode::TAXI)) {
646 20 : pars.push_back(new SUMOVehicleParameter());
647 10 : pars.back()->vtypeid = DEFAULT_TAXITYPE_ID;
648 10 : pars.back()->id = mode;
649 10 : modeSet |= SVC_TAXI;
650 257 : } else if (mode == toString(PersonMode::PUBLIC)) {
651 257 : pars.push_back(nullptr);
652 257 : modeSet |= SVC_BUS;
653 0 : } else if (mode == toString(PersonMode::WALK)) {
654 : // do nothing
655 : } else {
656 0 : throw TraCIException("Unknown person mode '" + mode + "'.");
657 : }
658 385 : }
659 385 : if (pars.empty()) {
660 39 : pars.push_back(nullptr);
661 : }
662 : // interpret default arguments
663 385 : const MSVehicleType* pedType = vehControl.hasVType(pType) ? vehControl.getVType(pType) : vehControl.getVType(DEFAULT_PEDTYPE_ID);
664 385 : SUMOTime departStep = TIME2STEPS(depart);
665 385 : if (depart < 0) {
666 379 : departStep = MSNet::getInstance()->getCurrentTimeStep();
667 : }
668 385 : if (speed < 0) {
669 : speed = MIN2(pedType->getMaxSpeed(), pedType->getDesiredMaxSpeed());
670 : }
671 385 : if (walkFactor < 0) {
672 379 : walkFactor = OptionsCont::getOptions().getFloat("persontrip.walkfactor");
673 : }
674 1155 : const double externalFactor = StringUtils::toDouble(pedType->getParameter().getParameter("externalEffortFactor", "100"));
675 385 : if (departPos < 0) {
676 0 : departPos += fromEdge->getLength();
677 : }
678 385 : if (arrivalPos == INVALID_DOUBLE_VALUE) {
679 54 : arrivalPos = toEdge->getLength() / 2;
680 331 : } else if (arrivalPos < 0) {
681 0 : arrivalPos += toEdge->getLength();
682 : }
683 385 : if (departPos < 0 || departPos >= fromEdge->getLength()) {
684 12 : throw TraCIException("Invalid depart position " + toString(departPos) + " for edge '" + from + "'.");
685 : }
686 379 : if (arrivalPos < 0 || arrivalPos >= toEdge->getLength()) {
687 0 : throw TraCIException("Invalid arrival position " + toString(arrivalPos) + " for edge '" + to + "'.");
688 : }
689 : double minCost = std::numeric_limits<double>::max();
690 764 : MSTransportableRouter& router = MSNet::getInstance()->getIntermodalRouter(0, routingMode);
691 1051 : for (SUMOVehicleParameter* vehPar : pars) {
692 : std::vector<TraCIStage> resultCand;
693 : SUMOVehicle* vehicle = nullptr;
694 672 : if (vehPar != nullptr) {
695 382 : MSVehicleType* type = MSNet::getInstance()->getVehicleControl().getVType(vehPar->vtypeid);
696 382 : if (type == nullptr) {
697 0 : throw TraCIException("Unknown vehicle type '" + vehPar->vtypeid + "'.");
698 : }
699 382 : if (type->getVehicleClass() != SVC_IGNORING && (fromEdge->getPermissions() & type->getVehicleClass()) == 0) {
700 48 : WRITE_WARNINGF(TL("Ignoring vehicle type '%' when performing intermodal routing because it is not allowed on the start edge '%'."), type->getID(), from);
701 : } else {
702 740 : ConstMSRoutePtr const routeDummy = std::make_shared<MSRoute>(vehPar->id, ConstMSEdgeVector({ fromEdge }), false, nullptr, std::vector<SUMOVehicleParameter::Stop>());
703 370 : vehicle = vehControl.buildVehicle(vehPar, routeDummy, type, !MSGlobals::gCheckRoutes);
704 : // we need to fix the speed factor here for deterministic results
705 370 : vehicle->setChosenSpeedFactor(type->getSpeedFactor().getParameter()[0]);
706 : }
707 : }
708 : std::vector<MSTransportableRouter::TripItem> items;
709 1344 : if (router.compute(fromEdge, toEdge, departPos, "", arrivalPos, destStop,
710 : speed * walkFactor, vehicle, modeSet, departStep, items, externalFactor)) {
711 : double cost = 0;
712 2247 : for (std::vector<MSTransportableRouter::TripItem>::iterator it = items.begin(); it != items.end(); ++it) {
713 1575 : if (!it->edges.empty()) {
714 3910 : resultCand.push_back(TraCIStage((it->line == "" ? STAGE_WALKING : STAGE_DRIVING), it->vType, it->line, it->destStop));
715 4620 : for (const MSEdge* e : it->edges) {
716 3045 : resultCand.back().edges.push_back(e->getID());
717 : }
718 1575 : resultCand.back().travelTime = it->traveltime;
719 1575 : resultCand.back().cost = it->cost;
720 1575 : resultCand.back().length = it->length;
721 1575 : resultCand.back().intended = it->intended;
722 1575 : resultCand.back().depart = it->depart;
723 1575 : resultCand.back().departPos = it->departPos;
724 1575 : resultCand.back().arrivalPos = it->arrivalPos;
725 1575 : resultCand.back().description = it->description;
726 : }
727 1575 : cost += it->cost;
728 : }
729 672 : if (cost < minCost) {
730 : minCost = cost;
731 409 : result = resultCand;
732 : }
733 : }
734 672 : if (vehicle != nullptr) {
735 370 : vehControl.deleteVehicle(vehicle, true);
736 : }
737 672 : }
738 379 : return result;
739 12 : }
740 :
741 :
742 : std::string
743 4049 : Simulation::getParameter(const std::string& objectID, const std::string& key) {
744 8098 : if (StringUtils::startsWith(key, "chargingStation.")) {
745 36 : const std::string attrName = key.substr(16);
746 36 : MSChargingStation* cs = static_cast<MSChargingStation*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_CHARGING_STATION));
747 36 : if (cs == nullptr) {
748 12 : throw TraCIException("Invalid chargingStation '" + objectID + "'");
749 : }
750 60 : if (attrName == toString(SUMO_ATTR_TOTALENERGYCHARGED)) {
751 6 : return toString(cs->getTotalCharged());
752 24 : } else if (attrName == toString(SUMO_ATTR_NAME)) {
753 6 : return toString(cs->getMyName());
754 18 : } else if (attrName == "lane") {
755 6 : return cs->getLane().getID();
756 12 : } else if (cs->hasParameter(attrName)) {
757 24 : return cs->getParameter(attrName);
758 : } else {
759 12 : throw TraCIException("Invalid chargingStation parameter '" + attrName + "'");
760 : }
761 8026 : } else if (StringUtils::startsWith(key, "overheadWire.")) {
762 0 : const std::string attrName = key.substr(16);
763 0 : MSOverheadWire* cs = static_cast<MSOverheadWire*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_OVERHEAD_WIRE_SEGMENT));
764 0 : if (cs == 0) {
765 0 : throw TraCIException("Invalid overhead wire '" + objectID + "'");
766 : }
767 0 : if (attrName == toString(SUMO_ATTR_TOTALENERGYCHARGED)) {
768 0 : return toString(cs->getTotalCharged());
769 0 : } else if (attrName == toString(SUMO_ATTR_NAME)) {
770 0 : return toString(cs->getMyName());
771 : } else {
772 0 : throw TraCIException("Invalid overhead wire parameter '" + attrName + "'");
773 : }
774 8026 : } else if (StringUtils::startsWith(key, "net.")) {
775 0 : const std::string attrName = key.substr(4);
776 0 : Position b = GeoConvHelper::getFinal().getOffsetBase();
777 0 : if (attrName == toString(SUMO_ATTR_NET_OFFSET)) {
778 0 : return toString(GeoConvHelper::getFinal().getOffsetBase());
779 : } else {
780 0 : throw TraCIException("Invalid net parameter '" + attrName + "'");
781 : }
782 8026 : } else if (StringUtils::startsWith(key, "parkingArea.")) {
783 31 : const std::string attrName = key.substr(12);
784 31 : MSParkingArea* pa = static_cast<MSParkingArea*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_PARKING_AREA));
785 31 : if (pa == nullptr) {
786 0 : throw TraCIException("Invalid parkingArea '" + objectID + "'");
787 : }
788 31 : if (attrName == "capacity") {
789 7 : return toString(pa->getCapacity());
790 24 : } else if (attrName == "occupancy") {
791 6 : return toString(pa->getOccupancyIncludingBlocked());
792 18 : } else if (attrName == toString(SUMO_ATTR_NAME)) {
793 6 : return toString(pa->getMyName());
794 12 : } else if (attrName == "lane") {
795 6 : return pa->getLane().getID();
796 6 : } else if (pa->hasParameter(attrName)) {
797 12 : return pa->getParameter(attrName);
798 : } else {
799 0 : throw TraCIException("Invalid parkingArea parameter '" + attrName + "'");
800 : }
801 7964 : } else if (StringUtils::startsWith(key, "busStop.")) {
802 18 : const std::string attrName = key.substr(8);
803 18 : MSStoppingPlace* bs = static_cast<MSStoppingPlace*>(MSNet::getInstance()->getStoppingPlace(objectID, SUMO_TAG_BUS_STOP));
804 18 : if (bs == nullptr) {
805 0 : throw TraCIException("Invalid busStop '" + objectID + "'");
806 : }
807 18 : if (attrName == toString(SUMO_ATTR_NAME)) {
808 6 : return toString(bs->getMyName());
809 12 : } else if (attrName == "lane") {
810 6 : return bs->getLane().getID();
811 6 : } else if (bs->hasParameter(attrName)) {
812 12 : return bs->getParameter(attrName);
813 : } else {
814 0 : throw TraCIException("Invalid busStop parameter '" + attrName + "'");
815 : }
816 7928 : } else if (StringUtils::startsWith(key, "device.tripinfo.")) {
817 3952 : if (objectID != "") {
818 0 : throw TraCIException("Simulation parameter '" + key + "' is not supported for object id '" + objectID
819 0 : + "'. Use empty id for global device parameers or vehicle domain for vehicle specific parameters");
820 : }
821 3952 : const std::string attrName = key.substr(16);
822 3952 : return MSDevice_Tripinfo::getGlobalParameter(attrName);
823 12 : } else if (objectID == "") {
824 12 : return MSNet::getInstance()->getParameter(key, "");
825 : } else {
826 12 : throw TraCIException("Simulation parameter '" + key + "' is not supported for object id '" + objectID + "'. Use empty id for generic network parameters");
827 : }
828 : }
829 :
830 0 : LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(Simulation)
831 :
832 : void
833 12 : Simulation::setParameter(const std::string& objectID, const std::string& key, const std::string& value) {
834 12 : if (objectID == "") {
835 6 : MSNet::getInstance()->setParameter(key, value);
836 : } else {
837 12 : throw TraCIException("Setting simulation parameter '" + key + "' is not supported for object id '" + objectID + "'. Use empty id for generic network parameters");
838 : }
839 6 : }
840 :
841 : void
842 6 : Simulation::setScale(double value) {
843 6 : MSNet::getInstance()->getVehicleControl().setScale(value);
844 6 : }
845 :
846 : void
847 7 : Simulation::clearPending(const std::string& routeID) {
848 7 : MSNet::getInstance()->getInsertionControl().clearPendingVehicles(routeID);
849 7 : }
850 :
851 :
852 : void
853 76 : Simulation::saveState(const std::string& fileName) {
854 76 : MSStateHandler::saveState(fileName, MSNet::getInstance()->getCurrentTimeStep());
855 76 : }
856 :
857 : double
858 234 : Simulation::loadState(const std::string& fileName) {
859 468 : long before = PROGRESS_BEGIN_TIME_MESSAGE("Loading state from '" + fileName + "'");
860 : try {
861 234 : const SUMOTime newTime = MSNet::getInstance()->loadState(fileName, false);
862 222 : Helper::clearStateChanges();
863 222 : Helper::clearSubscriptions();
864 222 : PROGRESS_TIME_MESSAGE(before);
865 222 : return STEPS2TIME(newTime);
866 12 : } catch (const IOError& e) {
867 12 : throw TraCIException("Loading state from '" + fileName + "' failed. " + e.what());
868 12 : } catch (const ProcessError& e) {
869 12 : throw TraCIException("Loading state from '" + fileName + "' failed, check whether SUMO versions match. " + e.what());
870 6 : }
871 : }
872 :
873 : void
874 7 : Simulation::writeMessage(const std::string& msg) {
875 7 : WRITE_MESSAGE(msg);
876 7 : }
877 :
878 :
879 : void
880 1416 : Simulation::storeShape(PositionVector& shape) {
881 2832 : shape = GeoConvHelper::getFinal().getConvBoundary().getShape(true);
882 1416 : }
883 :
884 :
885 : std::shared_ptr<VariableWrapper>
886 263 : Simulation::makeWrapper() {
887 263 : return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
888 : }
889 :
890 :
891 : bool
892 6768343 : Simulation::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
893 6768343 : switch (variable) {
894 262114 : case VAR_TIME:
895 262114 : return wrapper->wrapDouble(objID, variable, getTime());
896 6 : case VAR_TIME_STEP:
897 6 : return wrapper->wrapInt(objID, variable, (int)getCurrentTime());
898 6 : case VAR_END:
899 6 : return wrapper->wrapDouble(objID, variable, getEndTime());
900 0 : case VAR_LOADED_VEHICLES_NUMBER:
901 0 : return wrapper->wrapInt(objID, variable, getLoadedNumber());
902 40 : case VAR_LOADED_VEHICLES_IDS:
903 40 : return wrapper->wrapStringList(objID, variable, getLoadedIDList());
904 0 : case VAR_DEPARTED_VEHICLES_NUMBER:
905 0 : return wrapper->wrapInt(objID, variable, getDepartedNumber());
906 62 : case VAR_DEPARTED_VEHICLES_IDS:
907 62 : return wrapper->wrapStringList(objID, variable, getDepartedIDList());
908 0 : case VAR_TELEPORT_STARTING_VEHICLES_NUMBER:
909 0 : return wrapper->wrapInt(objID, variable, getStartingTeleportNumber());
910 0 : case VAR_TELEPORT_STARTING_VEHICLES_IDS:
911 0 : return wrapper->wrapStringList(objID, variable, getStartingTeleportIDList());
912 0 : case VAR_TELEPORT_ENDING_VEHICLES_NUMBER:
913 0 : return wrapper->wrapInt(objID, variable, getEndingTeleportNumber());
914 0 : case VAR_TELEPORT_ENDING_VEHICLES_IDS:
915 0 : return wrapper->wrapStringList(objID, variable, getEndingTeleportIDList());
916 0 : case VAR_ARRIVED_VEHICLES_NUMBER:
917 0 : return wrapper->wrapInt(objID, variable, getArrivedNumber());
918 0 : case VAR_ARRIVED_VEHICLES_IDS:
919 0 : return wrapper->wrapStringList(objID, variable, getArrivedIDList());
920 0 : case VAR_PARKING_STARTING_VEHICLES_NUMBER:
921 0 : return wrapper->wrapInt(objID, variable, getParkingStartingVehiclesNumber());
922 0 : case VAR_PARKING_STARTING_VEHICLES_IDS:
923 0 : return wrapper->wrapStringList(objID, variable, getParkingStartingVehiclesIDList());
924 0 : case VAR_PARKING_ENDING_VEHICLES_NUMBER:
925 0 : return wrapper->wrapInt(objID, variable, getParkingEndingVehiclesNumber());
926 0 : case VAR_PARKING_ENDING_VEHICLES_IDS:
927 0 : return wrapper->wrapStringList(objID, variable, getParkingEndingVehiclesIDList());
928 0 : case VAR_STOP_STARTING_VEHICLES_NUMBER:
929 0 : return wrapper->wrapInt(objID, variable, getStopStartingVehiclesNumber());
930 0 : case VAR_STOP_STARTING_VEHICLES_IDS:
931 0 : return wrapper->wrapStringList(objID, variable, getStopStartingVehiclesIDList());
932 0 : case VAR_STOP_ENDING_VEHICLES_NUMBER:
933 0 : return wrapper->wrapInt(objID, variable, getStopEndingVehiclesNumber());
934 0 : case VAR_STOP_ENDING_VEHICLES_IDS:
935 0 : return wrapper->wrapStringList(objID, variable, getStopEndingVehiclesIDList());
936 0 : case VAR_COLLIDING_VEHICLES_NUMBER:
937 0 : return wrapper->wrapInt(objID, variable, getCollidingVehiclesNumber());
938 0 : case VAR_COLLIDING_VEHICLES_IDS:
939 0 : return wrapper->wrapStringList(objID, variable, getCollidingVehiclesIDList());
940 0 : case VAR_EMERGENCYSTOPPING_VEHICLES_NUMBER:
941 0 : return wrapper->wrapInt(objID, variable, getEmergencyStoppingVehiclesNumber());
942 0 : case VAR_EMERGENCYSTOPPING_VEHICLES_IDS:
943 0 : return wrapper->wrapStringList(objID, variable, getEmergencyStoppingVehiclesIDList());
944 0 : case VAR_DEPARTED_PERSONS_NUMBER:
945 0 : return wrapper->wrapInt(objID, variable, getDepartedPersonNumber());
946 0 : case VAR_DEPARTED_PERSONS_IDS:
947 0 : return wrapper->wrapStringList(objID, variable, getDepartedPersonIDList());
948 0 : case VAR_ARRIVED_PERSONS_NUMBER:
949 0 : return wrapper->wrapInt(objID, variable, getArrivedPersonNumber());
950 0 : case VAR_ARRIVED_PERSONS_IDS:
951 0 : return wrapper->wrapStringList(objID, variable, getArrivedPersonIDList());
952 4 : case VAR_SCALE:
953 4 : return wrapper->wrapDouble(objID, variable, getScale());
954 117 : case VAR_DELTA_T:
955 117 : return wrapper->wrapDouble(objID, variable, getDeltaT());
956 5 : case VAR_OPTION:
957 10 : return wrapper->wrapString(objID, variable, getOption(objID));
958 6503265 : case VAR_MIN_EXPECTED_VEHICLES:
959 6503265 : return wrapper->wrapInt(objID, variable, getMinExpectedNumber());
960 4 : case VAR_BUS_STOP_ID_LIST:
961 4 : return wrapper->wrapStringList(objID, variable, getBusStopIDList());
962 9 : case VAR_BUS_STOP_WAITING:
963 9 : return wrapper->wrapInt(objID, variable, getBusStopWaiting(objID));
964 125 : case VAR_BUS_STOP_WAITING_IDS:
965 125 : return wrapper->wrapStringList(objID, variable, getBusStopWaitingIDList(objID));
966 24 : case VAR_PENDING_VEHICLES:
967 24 : return wrapper->wrapStringList(objID, variable, getPendingVehicles());
968 2561 : case libsumo::VAR_PARAMETER:
969 2561 : paramData->readUnsignedByte();
970 7643 : return wrapper->wrapString(objID, variable, getParameter(objID, paramData->readString()));
971 0 : case libsumo::VAR_PARAMETER_WITH_KEY:
972 0 : paramData->readUnsignedByte();
973 0 : return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, paramData->readString()));
974 : default:
975 : return false;
976 : }
977 : }
978 : }
979 :
980 :
981 : /****************************************************************************/
|