Eclipse SUMO - Simulation of Urban MObility
libsumo/TrafficLight.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3// Copyright (C) 2017-2022 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/****************************************************************************/
21// C++ TraCI client API implementation
22/****************************************************************************/
23#include <config.h>
24
26#include <microsim/MSLane.h>
27#include <microsim/MSEdge.h>
28#include <microsim/MSNet.h>
30#include <microsim/MSStop.h>
43#include "Helper.h"
44#include "TrafficLight.h"
45
46//#define DEBUG_CONSTRAINT_DEADLOCK
47
48namespace libsumo {
49// ===========================================================================
50// static member initializations
51// ===========================================================================
52SubscriptionResults TrafficLight::mySubscriptionResults;
53ContextSubscriptionResults TrafficLight::myContextSubscriptionResults;
54
55
56// ===========================================================================
57// static member definitions
58// ===========================================================================
59std::vector<std::string>
60TrafficLight::getIDList() {
62}
63
64
65int
66TrafficLight::getIDCount() {
67 return (int)getIDList().size();
68}
69
70
71std::string
72TrafficLight::getRedYellowGreenState(const std::string& tlsID) {
74}
75
76
77std::vector<TraCILogic>
78TrafficLight::getAllProgramLogics(const std::string& tlsID) {
79 std::vector<TraCILogic> result;
80 const std::vector<MSTrafficLightLogic*> logics = Helper::getTLS(tlsID).getAllLogics();
81 for (MSTrafficLightLogic* logic : logics) {
82 TraCILogic l(logic->getProgramID(), (int)logic->getLogicType(), logic->getCurrentPhaseIndex());
83 l.subParameter = logic->getParametersMap();
84 for (const MSPhaseDefinition* const phase : logic->getPhases()) {
85 l.phases.emplace_back(new TraCIPhase(STEPS2TIME(phase->duration), phase->getState(),
86 STEPS2TIME(phase->minDuration), STEPS2TIME(phase->maxDuration),
87 phase->getNextPhases(), phase->getName()));
88 }
89 result.emplace_back(l);
90 }
91 return result;
92}
93
94
95std::vector<std::string>
96TrafficLight::getControlledJunctions(const std::string& tlsID) {
97 std::set<std::string> junctionIDs;
99 for (const MSTrafficLightLogic::LinkVector& llinks : links) {
100 for (const MSLink* l : llinks) {
101 junctionIDs.insert(l->getJunction()->getID());
102 }
103 }
104 return std::vector<std::string>(junctionIDs.begin(), junctionIDs.end());
105}
106
107
108std::vector<std::string>
109TrafficLight::getControlledLanes(const std::string& tlsID) {
110 std::vector<std::string> laneIDs;
112 for (const MSTrafficLightLogic::LaneVector& llanes : lanes) {
113 for (const MSLane* l : llanes) {
114 laneIDs.push_back(l->getID());
115 }
116 }
117 return laneIDs;
118}
119
120
121std::vector<std::vector<TraCILink> >
122TrafficLight::getControlledLinks(const std::string& tlsID) {
123 std::vector<std::vector<TraCILink> > result;
126 for (int i = 0; i < (int)lanes.size(); ++i) {
127 std::vector<TraCILink> subList;
128 const MSTrafficLightLogic::LaneVector& llanes = lanes[i];
129 const MSTrafficLightLogic::LinkVector& llinks = links[i];
130 // number of links controlled by this signal (signal i)
131 for (int j = 0; j < (int)llanes.size(); ++j) {
132 MSLink* link = llinks[j];
133 // approached non-internal lane (if any)
134 const std::string to = link->getLane() != nullptr ? link->getLane()->getID() : "";
135 // approached "via", internal lane (if any)
136 const std::string via = link->getViaLane() != nullptr ? link->getViaLane()->getID() : "";
137 subList.emplace_back(TraCILink(llanes[j]->getID(), via, to));
138 }
139 result.emplace_back(subList);
140 }
141 return result;
142}
143
144
145std::string
146TrafficLight::getProgram(const std::string& tlsID) {
147 return Helper::getTLS(tlsID).getActive()->getProgramID();
148}
149
150
151int
152TrafficLight::getPhase(const std::string& tlsID) {
154}
155
156
157std::string
158TrafficLight::getPhaseName(const std::string& tlsID) {
160}
161
162
163double
164TrafficLight::getPhaseDuration(const std::string& tlsID) {
165 return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getCurrentPhaseDef().duration);
166}
167
168
169double
170TrafficLight::getNextSwitch(const std::string& tlsID) {
171 return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getNextSwitchTime());
172}
173
174int
175TrafficLight::getServedPersonCount(const std::string& tlsID, int index) {
176 MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
177 if (index < 0 || active->getPhaseNumber() <= index) {
178 throw TraCIException("The phase index " + toString(index) + " is not in the allowed range [0,"
179 + toString(active->getPhaseNumber() - 1) + "].");
180 }
181 // find all crossings which have a green light in that phas
182 int result = 0;
183
184 const std::string& state = active->getPhases()[index]->getState();
185 for (int i = 0; i < (int)state.size(); i++) {
186 for (MSLink* link : active->getLinksAt(i)) {
187 if (link->getLane()->getEdge().isCrossing()) {
188 // walking forwards across
189 for (MSTransportable* person : link->getLaneBefore()->getEdge().getPersons()) {
190 if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLane()->getEdge().getID()) {
191 result += 1;
192 }
193 }
194 // walking backwards across
195 MSLane* walkingAreaAcross = link->getLane()->getLinkCont().front()->getLane();
196 for (MSTransportable* person : walkingAreaAcross->getEdge().getPersons()) {
197 if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLane()->getEdge().getID()) {
198 result += 1;
199 }
200 }
201 } else if (link->getLaneBefore()->getEdge().isCrossing()) {
202 // walking backwards across (in case both sides are separately controlled)
203 for (MSTransportable* person : link->getLane()->getEdge().getPersons()) {
204 if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLaneBefore()->getEdge().getID()) {
205 result += 1;
206 }
207 }
208 }
209 }
210 }
211 return result;
212}
213
214std::vector<std::string>
215TrafficLight::getBlockingVehicles(const std::string& tlsID, int linkIndex) {
216 std::vector<std::string> result;
217 // for railsignals we cannot use the "online" program
218 MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
219 if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
220 throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
221 + toString(active->getNumLinks() - 1) + "].");
222 }
223 for (const SUMOVehicle* veh : active->getBlockingVehicles(linkIndex)) {
224 result.push_back(veh->getID());
225 }
226 return result;
227}
228
229std::vector<std::string>
230TrafficLight::getRivalVehicles(const std::string& tlsID, int linkIndex) {
231 std::vector<std::string> result;
232 MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
233 if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
234 throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
235 + toString(active->getNumLinks() - 1) + "].");
236 }
237 for (const SUMOVehicle* veh : active->getRivalVehicles(linkIndex)) {
238 result.push_back(veh->getID());
239 }
240 return result;
241}
242
243std::vector<std::string>
244TrafficLight::getPriorityVehicles(const std::string& tlsID, int linkIndex) {
245 std::vector<std::string> result;
246 MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
247 if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
248 throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
249 + toString(active->getNumLinks() - 1) + "].");
250 }
251 for (const SUMOVehicle* veh : active->getPriorityVehicles(linkIndex)) {
252 result.push_back(veh->getID());
253 }
254 return result;
255}
256
257std::vector<TraCISignalConstraint>
258TrafficLight::getConstraints(const std::string& tlsID, const std::string& tripId) {
259 std::vector<TraCISignalConstraint> result;
260 MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
261 MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
262 if (s == nullptr) {
263 throw TraCIException("'" + tlsID + "' is not a rail signal");
264 }
265 for (auto item : s->getConstraints()) {
266 if (tripId != "" && tripId != item.first) {
267 continue;
268 }
269 for (MSRailSignalConstraint* c : item.second) {
270 result.push_back(buildConstraint(tlsID, item.first, c));
271 }
272 }
273 return result;
274}
275
276std::vector<TraCISignalConstraint>
277TrafficLight::getConstraintsByFoe(const std::string& foeSignal, const std::string& foeId) {
278 // retrieve all constraints that have the given foeSignal (optionally filtered by foeId)
279 // @note could improve efficiency by storing a map of rail signals in MSRailSignalControl
280 std::vector<TraCISignalConstraint> result;
281 for (const std::string& tlsID : getIDList()) {
282 MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
283 MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
284 if (s != nullptr) {
285 for (auto item : s->getConstraints()) {
286 for (MSRailSignalConstraint* cand : item.second) {
288 if (pc != nullptr && pc->myFoeSignal->getID() == foeSignal
289 && (foeId == "" || pc->myTripId == foeId)) {
290 result.push_back(buildConstraint(s->getID(), item.first, pc));
291 }
292 }
293 }
294 }
295 }
296 return result;
297}
298
299std::vector<TraCISignalConstraint>
300TrafficLight::swapConstraints(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId) {
301#ifdef DEBUG_CONSTRAINT_DEADLOCK
302 std::cout << "swapConstraints tlsId=" << tlsID << " tripId=" << tripId << " foeSignal=" << foeSignal << " foeId=" << foeId << "\n";
303#endif
304 MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
305 MSTrafficLightLogic* const active2 = Helper::getTLS(foeSignal).getDefault();
306 MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
307 MSRailSignal* s2 = dynamic_cast<MSRailSignal*>(active2);
308 if (s == nullptr) {
309 throw TraCIException("'" + tlsID + "' is not a rail signal");
310 }
311 if (s2 == nullptr) {
312 throw TraCIException("'" + foeSignal + "' is not a rail signal");
313 }
315 for (auto item : s->getConstraints()) {
316 if (tripId == item.first) {
317 for (MSRailSignalConstraint* cand : item.second) {
319 if (pc != nullptr && pc->myFoeSignal->getID() == foeSignal && pc->myTripId == foeId) {
320 c = pc;
321 break;
322 }
323 }
324 break;
325 }
326 }
327 if (c != nullptr) {
328 const int limit = c->myLimit;
329 // the two constraints are complementary so we actually remove rather than deactivate to avoid redundant conflict information
331 s->removeConstraint(tripId, c);
332 s2->addConstraint(foeId, new MSRailSignalConstraint_Predecessor(type, s, tripId, limit, true));
333 return findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
334 } else {
335 throw TraCIException("Rail signal '" + tlsID + "' does not have a constraint for tripId '" + tripId + "' with foeSignal '" + foeSignal + "' and foeId '" + foeId + "'");
336 }
337}
338
339void
340TrafficLight::removeConstraints(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId) {
341 // remove all constraints that have the given foeId
342 // @note could improve efficiency by storing a map of rail signals in MSRailSignalControl
343 for (const std::string& tlsCand : getIDList()) {
344 if (tlsID == "" || tlsCand == tlsID) {
345 MSTrafficLightLogic* const active = Helper::getTLS(tlsCand).getDefault();
346 MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
347 if (s != nullptr) {
348 for (auto item : s->getConstraints()) {
349 if (tripId == "" || item.first == tripId) {
350 for (MSRailSignalConstraint* cand : item.second) {
352 if (pc != nullptr
353 && (foeId == "" || pc->myTripId == foeId)
354 && (foeSignal == "" || pc->myFoeSignal->getID() == foeSignal)) {
355 cand->setActive(false);
356 }
357 }
358 }
359 }
360 }
361 }
362 }
363}
364
365
366void
367TrafficLight::updateConstraints(const std::string& vehID, std::string tripId) {
368 // Removes all constraints that can no longer be met because the route of
369 // vehID does not pass the signal involved in the constraint with the given tripId.
370 // This includes constraints on tripId as well as constraints where tripId is the foeId.
371
372 MSBaseVehicle* veh = Helper::getVehicle(vehID);
373 std::string curTripId = veh->getParameter().getParameter("tripId", veh->getID());
374 tripId = tripId == "" ? curTripId : tripId;
375
376 // find signals and tripId along the route of veh
377 std::map<const MSRailSignal*, std::set<std::string> > onRoute;
378 const ConstMSEdgeVector& route = veh->getRoute().getEdges();
379 auto routeIt = veh->getCurrentRouteEdge();
380 for (const MSStop& stop : veh->getStops()) {
381 for (auto it = routeIt; it < stop.edge; it++) {
382 const MSEdge* edge = *it;
384 if (it + 1 != route.end()) {
385 const MSEdge* next = *(it + 1);
386 const MSLink* link = edge->getLanes()[0]->getLinkTo(next->getLanes()[0]);
387 if (link != nullptr && link->getTLLogic() != nullptr) {
388 const MSRailSignal* s = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
389 onRoute[s].insert(curTripId);
390 }
391 }
392 }
393 }
394 if (stop.pars.tripId != "") {
395 curTripId = stop.pars.tripId;
396 }
397 routeIt = stop.edge;
398 }
399 for (auto it = routeIt; it < route.end(); it++) {
400 const MSEdge* edge = *it;
402 if (it + 1 != route.end()) {
403 const MSEdge* next = *(it + 1);
404 const MSLink* link = edge->getLanes()[0]->getLinkTo(next->getLanes()[0]);
405 if (link != nullptr && link->getTLLogic() != nullptr) {
406 const MSRailSignal* s = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
407 onRoute[s].insert(curTripId);
408 }
409 }
410 }
411 }
412 //for (auto item : onRoute) {
413 // std::cout << " s=" << item.first->getID() << " @" << item.first << " ids=" << toString(item.second) << "\n";
414 //}
415
416 // check relevance for all active contraints
418
419 // record outdated constraints on and by the vehicle
420 std::vector<MSRailSignalConstraint*> onVeh;
421 std::vector<std::pair<std::string, MSRailSignalConstraint*> > byVeh;
422
423 for (auto item : s->getConstraints()) {
424 for (MSRailSignalConstraint* cand : item.second) {
426 if (pc != nullptr && !pc->cleared() && pc->isActive()) {
427 if (item.first == tripId) {
428 if (onRoute[s].count(tripId) == 0) {
429 // constraint on our veh no longer relevant
430 onVeh.push_back(cand);
431 }
432 } else if (pc->myTripId == tripId) {
433 if (onRoute[pc->myFoeSignal].count(tripId) == 0) {
434 // constraint by our veh no longer relevant
435 byVeh.push_back(std::make_pair(item.first, cand));
436 }
437 }
438 }
439 }
440 }
441 for (MSRailSignalConstraint* c : onVeh) {
442 s->removeConstraint(tripId, c);
443 }
444 for (auto item : byVeh) {
445 s->removeConstraint(item.first, item.second);
446 }
447 }
448}
449
450
451std::vector<TraCISignalConstraint>
452TrafficLight::findConstraintsDeadLocks(const std::string& foeId, const std::string& tripId, const std::string& foeSignal, const std::string& tlsID) {
453 std::vector<TraCISignalConstraint> result;
454 // find circular constraints (deadlock)
455 // foeId is now constrainted by tripId and assumed to follow tripId on the
456 // same track without possibility of overtaking
457 // we look for a third vehicle foeId2 where
458 // tripId waits for foeId2 and foeId2 waits on foeId
459 std::map<std::string, TraCISignalConstraint> constraintsOnTripId;
460 std::map<std::string, TraCISignalConstraint> constrainedByFoeId;
461 std::set<std::string> foeId2Cands1;
462 std::set<std::string> foeId2Cands2;
463 for (MSRailSignal* s : MSRailSignalControl::getInstance().getSignals()) {
464 for (auto item : s->getConstraints()) {
465 for (MSRailSignalConstraint* cand : item.second) {
467 if (pc != nullptr && !pc->cleared() && pc->isActive()) {
468 if (item.first == tripId) {
469 // tripId waits for foe2
470 // @could there by more than one constraint on tripId by this foe2?
471 libsumo::TraCISignalConstraint tsc = buildConstraint(s->getID(), item.first, pc);
472 constraintsOnTripId[pc->myTripId] = tsc;
473 foeId2Cands1.insert(pc->myTripId);
474 for (std::string& futureFoe2Id : getFutureTripIds(pc->myTripId)) {
475 foeId2Cands1.insert(futureFoe2Id);
476 //tsc.foeId = futureFoe2Id; // if we do this, the constraint to swap will not be found
477 constraintsOnTripId[futureFoe2Id] = tsc;
478 }
479 } else if (pc->myTripId == foeId) {
480 // foeId2 waits for foe
481 libsumo::TraCISignalConstraint tsc = buildConstraint(s->getID(), item.first, pc);
482 constrainedByFoeId[item.first] = tsc;
483 foeId2Cands2.insert(item.first);
484 for (std::string& futureTripId : getFutureTripIds(item.first)) {
485 foeId2Cands2.insert(futureTripId);
486 //tsc.tripId = futureTripId; // if we do this, the constraint to swap will not be found
487 constrainedByFoeId[futureTripId] = tsc;
488 }
489 }
490 }
491 }
492 }
493 }
494#ifdef DEBUG_CONSTRAINT_DEADLOCK
495 std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << " tlsID=" << tlsID << "\n";
496 std::cout << " foeId2Cands1=" << toString(foeId2Cands1) << "\n";
497 std::cout << " foeId2Cands2=" << toString(foeId2Cands2) << "\n";
498#endif
499 if (foeId2Cands1.size() > 0) {
500 // foe2 might be constrained implicitly by foe due to following on the same track
501 // in this case foe must be on the route of foe2 between its current position and foeSignal
502
503 // we have to check this first because it also affects foeInsertion
504 // constraints if the foe is already inserted but hasn't yet passed the
505 // signal (cleared == false).
506 SUMOVehicle* foe = getVehicleByTripId(foeId);
507 if (foe != nullptr) {
508 const MSEdge* foeEdge = foe->getEdge();
509 const double foePos = foe->getPositionOnLane();
510 for (const std::string& foeId2 : foeId2Cands1) {
511 // tripId waits for foeId2
512 SUMOVehicle* foe2 = getVehicleByTripId(foeId2);
513 if (foe2 != nullptr) {
514 const ConstMSEdgeVector& foe2Route = foe2->getRoute().getEdges();
515 const TraCISignalConstraint& c = constraintsOnTripId[foeId2];
516 bool foeAhead = false;
517 for (int i = foe2->getRoutePosition(); i < (int)foe2Route.size(); i++) {
518 const MSEdge* e = foe2Route[i];
519 if (e == foeEdge &&
520 ((e != foe2->getEdge() || foe2->getPositionOnLane() < foePos)
521 || (foe->hasDeparted() && !foe2->hasDeparted())
522 || (!foe->hasDeparted() && !foe2->hasDeparted() &&
523 (foe->getParameter().depart < foe2->getParameter().depart
524 || (foe->getParameter().depart == foe2->getParameter().depart && foe->getNumericalID() < foe2->getNumericalID())))
525 )) {
526 foeAhead = true;
527#ifdef DEBUG_CONSTRAINT_DEADLOCK
528 std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
529 std::cout << " foeLeaderDeadlock foeEdge=" << foeEdge->getID() << " foe2=" << foe2->getParameter().getParameter("tripId", foe2->getID())
530 << " routePos=" << foe2->getRoutePosition() << " futureRPos=" << i << " e=" << e->getID()
531 //<< " foePos=" << foePos << " foe2Pos=" << foe2->getPositionOnLane()
532 << " " << constraintsOnTripId[foeId2].getString() << "\n";
533#endif
534 break;
535 }
536 if (e->getToJunction()->getID() == foeSignal
537 || e->getToJunction()->getID() == c.foeSignal) {
538 break;
539 }
540 }
541 if (foeAhead) {
542 // foe cannot wait for foe2 (since it's behind). Instead foe2 must wait for tripId
543 TraCISignalConstraint nc; // constraint after swap
544 nc.tripId = c.foeId;
545 nc.foeId = c.tripId;
546 nc.signalId = c.foeSignal;
547 nc.foeSignal = c.signalId;
548 nc.limit = c.limit;
549 nc.type = c.type;
550 nc.mustWait = true; // ???
551 nc.active = true;
552 result.push_back(nc);
553 // let foe wait for foe2
554 std::vector<TraCISignalConstraint> result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
555 result.insert(result.end(), result2.begin(), result2.end());
556
557 // Other deadlocks might not be valid anymore so we need a fresh recheck for remaining implicit or explicit deadlocks
558 const std::vector<TraCISignalConstraint>& result4 = findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
559 result.insert(result.end(), result4.begin(), result4.end());
560 return result;
561 }
562 }
563 }
564 }
565 }
566
567 if (foeId2Cands2.size() > 0) {
568 // tripId might be constrained implicitly by foe2 due to following on the same track
569 // in this case foe2 must be on the route of tripId between its current position and tlsID
570 // if foe2 then waits for foe, deadlock occurs
571
572 SUMOVehicle* ego = getVehicleByTripId(tripId);
573 if (ego != nullptr && (ego->hasDeparted() || !ego->getParameter().wasSet(VEHPARS_FORCE_REROUTE))) {
574 std::set<const MSEdge*> egoToSignal;
575 const double egoPos = ego->getPositionOnLane();
576 const ConstMSEdgeVector& egoRoute = ego->getRoute().getEdges();
577 for (int i = ego->getRoutePosition(); i < (int)egoRoute.size(); i++) {
578 const MSEdge* e = egoRoute[i];
579 egoToSignal.insert(e);
580 if (e->getToJunction()->getID() == tlsID) {
581 break;
582 }
583 }
584
585 for (const std::string& foeId2 : foeId2Cands2) {
586 // foeId2 waits for foe
587 SUMOVehicle* foe2 = getVehicleByTripId(foeId2);
588 //std::cout << " foe2=" << foe2->getID() << " edge=" << foe2->getEdge()->getID() << " egoToSignal=" << toString(egoToSignal) << "\n";
589 if (foe2 != nullptr) {
590 if (egoToSignal.count(foe2->getEdge()) != 0
591 && (foe2->getEdge() != ego->getEdge() || foe2->getPositionOnLane() > egoPos)) {
592 const TraCISignalConstraint& c = constrainedByFoeId[foeId2];
593#ifdef DEBUG_CONSTRAINT_DEADLOCK
594 std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
595 std::cout << " egoLeaderDeadlock foe2Edge=" << foe2->getEdge()->getID() << " foe2=" << foe2->getParameter().getParameter("tripId", foe2->getID())
596 << " " << c.getString() << "\n";
597#endif
598 // foe is already waiting for tripId (ego) and should also wait for foeId2
599 TraCISignalConstraint nc; // constraint after swap
600 nc.tripId = c.foeId;
601 nc.foeId = c.tripId;
602 nc.signalId = c.foeSignal;
603 nc.foeSignal = c.signalId;
604 nc.limit = c.limit;
605 nc.type = c.type;
606 nc.mustWait = true; // ???
607 nc.active = true;
608 result.push_back(nc);
609 // let foe wait for foe2
610 std::vector<TraCISignalConstraint> result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
611 result.insert(result.end(), result2.begin(), result2.end());
612
613 // Other deadlocks might not be valid anymore so we need a fresh recheck for remaining implicit or explicit deadlocks
614 const std::vector<TraCISignalConstraint>& result4 = findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
615 result.insert(result.end(), result4.begin(), result4.end());
616 return result;
617 }
618 }
619 }
620 } else if (ego != nullptr) {
621 WRITE_WARNING("Cannot check for all deadlocks on swapConstraints because the route for vehicle '" + ego->getID() + "' is not computed yet");
622 }
623 }
624
625 // find deadlock in explicit constraints
626 std::vector<std::string> foeIds2;
627 std::set_intersection(
628 foeId2Cands1.begin(), foeId2Cands1.end(),
629 foeId2Cands2.begin(), foeId2Cands2.end(),
630 std::back_inserter(foeIds2));
631#ifdef DEBUG_CONSTRAINT_DEADLOCK
632 std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
633 for (const std::string& foeId2 : foeIds2) {
634 std::cout << " deadlockId=" << foeId2 << " " << constraintsOnTripId[foeId2].getString() << " " << constrainedByFoeId[foeId2].getString() << "\n";
635 }
636#endif
637 if (foeIds2.size() > 0) {
638 TraCISignalConstraint c = constrainedByFoeId[foeIds2.front()];
639 if (c.type == MSRailSignalConstraint::ConstraintType::INSERTION_PREDECESSOR) {
640 // avoid swapping insertion constraint
641 c = constraintsOnTripId[foeIds2.front()];
642 }
643 TraCISignalConstraint nc; // constraint after swap
644 nc.tripId = c.foeId;
645 nc.foeId = c.tripId;
646 nc.signalId = c.foeSignal;
647 nc.foeSignal = c.signalId;
648 nc.limit = c.limit;
649 nc.type = c.type;
650 nc.mustWait = true; // ???
651 nc.active = true;
652 result.push_back(nc);
653 // let foe wait for foe2
654 const std::vector<TraCISignalConstraint>& result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
655 result.insert(result.end(), result2.begin(), result2.end());
656 if (foeIds2.size() > 1) {
657 // calling swapConstraints once may result in further swaps so we have to recheck for remaining deadlocks anew
658 const std::vector<TraCISignalConstraint>& result3 = findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
659 result.insert(result.end(), result3.begin(), result3.end());
660 }
661 }
662 return result;
663}
664
665
667TrafficLight::getVehicleByTripId(const std::string tripOrVehID) {
669 for (MSVehicleControl::constVehIt i = c.loadedVehBegin(); i != c.loadedVehEnd(); ++i) {
670 SUMOVehicle* veh = i->second;
671 if (veh->getParameter().getParameter("tripId", veh->getID()) == tripOrVehID) {
672 return veh;
673 }
674 }
675 return nullptr;
676}
677
678
679std::vector<std::string>
680TrafficLight::getFutureTripIds(const std::string vehID) {
681 std::vector<std::string> result;
683 if (veh) {
684 std::string tripId = veh->getParameter().getParameter("tripId");
685 if (tripId != "") {
686 result.push_back(tripId);
687 }
688 for (const MSStop& stop : veh->getStops()) {
689 if (stop.pars.tripId != "") {
690 result.push_back(stop.pars.tripId);
691 }
692 }
693 }
694 return result;
695}
696
697
698std::string
699TrafficLight::getParameter(const std::string& tlsID, const std::string& paramName) {
701 if (StringUtils::startsWith(paramName, "NEMA.") && tll->getLogicType() != TrafficLightType::NEMA) {
702 throw TraCIException("'" + tlsID + "' is not a NEMA controller");
703 }
704 return tll->getParameter(paramName, "");
705}
706
707
709
710
711void
712TrafficLight::setRedYellowGreenState(const std::string& tlsID, const std::string& state) {
713 Helper::getTLS(tlsID).setStateInstantiatingOnline(MSNet::getInstance()->getTLSControl(), state);
714}
715
716
717void
718TrafficLight::setPhase(const std::string& tlsID, const int index) {
719 MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
720 if (index < 0 || active->getPhaseNumber() <= index) {
721 throw TraCIException("The phase index " + toString(index) + " is not in the allowed range [0,"
722 + toString(active->getPhaseNumber() - 1) + "].");
723 }
725 const SUMOTime duration = active->getPhase(index).duration;
726 active->changeStepAndDuration(MSNet::getInstance()->getTLSControl(), cTime, index, duration);
727}
728
729void
730TrafficLight::setPhaseName(const std::string& tlsID, const std::string& name) {
731 MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
732 const_cast<MSPhaseDefinition&>(active->getCurrentPhaseDef()).setName(name);
733}
734
735
736void
737TrafficLight::setProgram(const std::string& tlsID, const std::string& programID) {
738 try {
739 Helper::getTLS(tlsID).switchTo(MSNet::getInstance()->getTLSControl(), programID);
740 } catch (ProcessError& e) {
741 throw TraCIException(e.what());
742 }
743}
744
745
746void
747TrafficLight::setPhaseDuration(const std::string& tlsID, const double phaseDuration) {
748 MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
750 active->changeStepAndDuration(MSNet::getInstance()->getTLSControl(), cTime, -1, TIME2STEPS(phaseDuration));
751}
752
753
754void
755TrafficLight::setProgramLogic(const std::string& tlsID, const TraCILogic& logic) {
757 // make sure index and phaseNo are consistent
758 if (logic.currentPhaseIndex >= (int)logic.phases.size()) {
759 throw TraCIException("set program: parameter index must be less than parameter phase number.");
760 }
761 std::vector<MSPhaseDefinition*> phases;
762 for (const std::shared_ptr<libsumo::TraCIPhase>& phase : logic.phases) {
763 MSPhaseDefinition* sumoPhase = new MSPhaseDefinition(TIME2STEPS(phase->duration), phase->state, phase->name);
764 sumoPhase->minDuration = TIME2STEPS(phase->minDur);
765 sumoPhase->maxDuration = TIME2STEPS(phase->maxDur);
766 sumoPhase->nextPhases = phase->next;
767 phases.push_back(sumoPhase);
768 }
769 if (vars.getLogic(logic.programID) == nullptr) {
771 int step = logic.currentPhaseIndex;
772 const std::string basePath = "";
773 MSTrafficLightLogic* tlLogic = nullptr;
774 SUMOTime nextSwitch = MSNet::getInstance()->getCurrentTimeStep() + phases[0]->duration;
775 switch ((TrafficLightType)logic.type) {
777 tlLogic = new MSActuatedTrafficLightLogic(tlc,
778 tlsID, logic.programID, 0,
779 phases, step, nextSwitch,
780 logic.subParameter, basePath);
781 break;
783 tlLogic = new NEMALogic(tlc,
784 tlsID, logic.programID, 0,
785 phases, step, nextSwitch,
786 logic.subParameter, basePath);
787 break;
789 tlLogic = new MSDelayBasedTrafficLightLogic(tlc,
790 tlsID, logic.programID, 0,
791 phases, step, nextSwitch,
792 logic.subParameter, basePath);
793 break;
795 tlLogic = new MSSimpleTrafficLightLogic(tlc,
796 tlsID, logic.programID, 0, TrafficLightType::STATIC,
797 phases, step, nextSwitch,
798 logic.subParameter);
799 break;
800 default:
801 throw TraCIException("Unsupported traffic light type '" + toString(logic.type) + "'");
802 }
803 vars.addLogic(logic.programID, tlLogic, true, true);
804 // XXX pass GUIDetectorBuilder when running with gui
806 tlLogic->init(db);
808 } else {
809 static_cast<MSSimpleTrafficLightLogic*>(vars.getLogic(logic.programID))->setPhases(phases, logic.currentPhaseIndex);
810 }
811}
812
813
814void
815TrafficLight::setParameter(const std::string& tlsID, const std::string& paramName, const std::string& value) {
817 if (StringUtils::startsWith(paramName, "NEMA.") && tll->getLogicType() != TrafficLightType::NEMA) {
818 throw TraCIException("'" + tlsID + "' is not a NEMA controller");
819 }
820 tll->setParameter(paramName, value);
821}
822
824
825void
826TrafficLight::setNemaSplits(const std::string& tlsID, const std::vector<double>& splits) {
827 setParameter(tlsID, "NEMA.splits", toString(splits));
828}
829
830void
831TrafficLight::setNemaMaxGreens(const std::string& tlsID, const std::vector<double>& maxGreens) {
832 setParameter(tlsID, "NEMA.maxGreens", toString(maxGreens));
833}
834
835void
836TrafficLight::setNemaCycleLength(const std::string& tlsID, double cycleLength) {
837 setParameter(tlsID, "NEMA.cycleLength", toString(cycleLength));
838}
839
840void
841TrafficLight::setNemaOffset(const std::string& tlsID, double offset) {
842 setParameter(tlsID, "NEMA.offset", toString(offset));
843}
844
845
847TrafficLight::buildConstraint(const std::string& tlsID, const std::string& tripId, MSRailSignalConstraint* constraint) {
848 TraCISignalConstraint c;
849 c.tripId = tripId;
851 if (pc == nullptr) {
852 // unsupported constraint
853 c.type = -1;
854 } else {
855 c.signalId = tlsID;
856 c.foeId = pc->myTripId;
857 c.foeSignal = pc->myFoeSignal->getID();
858 c.limit = pc->myLimit;
859 c.type = pc->getType();
860 c.mustWait = !pc->cleared() && pc->isActive();
861 c.active = pc->isActive();
862 c.param = constraint->getParametersMap();
863 }
864 return c;
865}
866
867
868std::shared_ptr<VariableWrapper>
869TrafficLight::makeWrapper() {
870 return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
871}
872
873
874bool
875TrafficLight::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
876 switch (variable) {
877 case TRACI_ID_LIST:
878 return wrapper->wrapStringList(objID, variable, getIDList());
879 case ID_COUNT:
880 return wrapper->wrapInt(objID, variable, getIDCount());
882 return wrapper->wrapString(objID, variable, getRedYellowGreenState(objID));
884 return wrapper->wrapStringList(objID, variable, getControlledLanes(objID));
885 case TL_CURRENT_PHASE:
886 return wrapper->wrapInt(objID, variable, getPhase(objID));
887 case VAR_NAME:
888 return wrapper->wrapString(objID, variable, getPhaseName(objID));
890 return wrapper->wrapString(objID, variable, getProgram(objID));
892 return wrapper->wrapDouble(objID, variable, getPhaseDuration(objID));
893 case TL_NEXT_SWITCH:
894 return wrapper->wrapDouble(objID, variable, getNextSwitch(objID));
896 return wrapper->wrapStringList(objID, variable, getControlledJunctions(objID));
898 paramData->readUnsignedByte();
899 return wrapper->wrapString(objID, variable, getParameter(objID, paramData->readString()));
901 paramData->readUnsignedByte();
902 return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, paramData->readString()));
903 default:
904 return false;
905 }
906}
907}
908
909
910/****************************************************************************/
long long int SUMOTime
Definition: GUI.h:36
std::vector< const MSEdge * > ConstMSEdgeVector
Definition: MSEdge.h:74
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:265
#define TL(string)
Definition: MsgHandler.h:282
#define STEPS2TIME(x)
Definition: SUMOTime.h:54
#define TIME2STEPS(x)
Definition: SUMOTime.h:56
const int VEHPARS_FORCE_REROUTE
TrafficLightType
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
#define LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(CLASS, DOM)
Definition: TraCIDefs.h:76
#define LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(CLASS)
Definition: TraCIDefs.h:123
An actuated (adaptive) traffic light logic.
The base class for microscopic and mesoscopic vehicles.
Definition: MSBaseVehicle.h:55
const SUMOVehicleParameter & getParameter() const
Returns the vehicle's parameter (including departure definition)
const MSRouteIterator & getCurrentRouteEdge() const
Returns an iterator pointing to the current edge in this vehicles route.
const std::list< MSStop > & getStops() const
const MSRoute & getRoute() const
Returns the current route.
An actuated traffic light logic based on time delay of approaching vehicles.
A road/street connecting two junctions.
Definition: MSEdge.h:77
const std::set< MSTransportable *, ComparatorNumericalIdLess > & getPersons() const
Returns this edge's persons set.
Definition: MSEdge.h:201
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:168
const MSJunction * getToJunction() const
Definition: MSEdge.h:415
SumoXMLNodeType getType() const
return the type of this Junction
Definition: MSJunction.h:130
Representation of a lane in the micro simulation.
Definition: MSLane.h:84
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:713
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.h:675
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:183
MSTLLogicControl & getTLSControl()
Returns the tls logics control.
Definition: MSNet.h:452
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:321
virtual void createTLWrapper(MSTrafficLightLogic *)
creates a wrapper for the given logic (see GUINet)
Definition: MSNet.h:578
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:379
const std::string & getNextEdge() const
return the list of internal edges if this person is walking and the pedestrian model allows it
Definition: MSPerson.cpp:550
The definition of a single phase of a tls logic.
SUMOTime maxDuration
The maximum duration of the phase.
SUMOTime minDuration
The minimum duration of the phase.
const std::string & getName() const
const std::string & getState() const
Returns the state within this phase.
SUMOTime duration
The duration of the phase.
std::vector< int > nextPhases
The index of the phase that suceeds this one (or -1)
const MSRailSignal * myFoeSignal
store the foe signal (for TraCI access)
bool cleared() const
whether the constraint has been met
const std::string myTripId
id of the predecessor that must already have passed
const int myLimit
the number of passed vehicles within which tripId must have occured
A base class for constraints.
virtual void setActive(bool active)=0
ConstraintType getType() const
ConstraintType getSwappedType() const
static MSRailSignalControl & getInstance()
const std::vector< MSRailSignal * > & getSignals() const
A signal for rails.
Definition: MSRailSignal.h:46
void addConstraint(const std::string &tripId, MSRailSignalConstraint *constraint)
register contraint for signal switching
const std::map< std::string, std::vector< MSRailSignalConstraint * > > & getConstraints() const
Definition: MSRailSignal.h:230
bool removeConstraint(const std::string &tripId, MSRailSignalConstraint *constraint)
remove contraint for signal switching
const ConstMSEdgeVector & getEdges() const
Definition: MSRoute.h:124
A fixed traffic light logic.
Definition: MSStop.h:44
Storage for all programs of a single tls.
void switchTo(MSTLLogicControl &tlc, const std::string &programID)
void setStateInstantiatingOnline(MSTLLogicControl &tlc, const std::string &state)
std::vector< MSTrafficLightLogic * > getAllLogics() const
MSTrafficLightLogic * getLogic(const std::string &programID) const
bool addLogic(const std::string &programID, MSTrafficLightLogic *logic, bool netWasLoaded, bool isNewDefault=true)
Adds a logic (program)
MSTrafficLightLogic * getActive() const
MSTrafficLightLogic * getDefault() const
return the default program (that last used program except TRACI_PROGRAM)
A class that stores and controls tls and switching of their programs.
std::vector< std::string > getAllTLIds() const
The parent class for traffic light logics.
const LinkVectorVector & getLinks() const
Returns the list of lists of all affected links.
std::vector< LaneVector > LaneVectorVector
Definition of a list that holds lists of lanes that do have the same attribute.
virtual const MSPhaseDefinition & getCurrentPhaseDef() const =0
Returns the definition of the current phase.
virtual int getPhaseNumber() const =0
Returns the number of phases.
virtual int getCurrentPhaseIndex() const =0
Returns the current index within the program.
std::vector< MSLane * > LaneVector
Definition of the list of arrival lanes subjected to this tls.
virtual VehicleVector getPriorityVehicles(int linkIndex)
return vehicles that approach the intersection/rail signal and have priority over vehicles that wish ...
virtual void changeStepAndDuration(MSTLLogicControl &tlcontrol, SUMOTime simStep, int step, SUMOTime stepDuration)=0
Changes the current phase and her duration.
virtual VehicleVector getBlockingVehicles(int linkIndex)
return vehicles that block the intersection/rail signal for vehicles that wish to pass the given link...
virtual const MSPhaseDefinition & getPhase(int givenstep) const =0
Returns the definition of the phase from the given position within the plan.
virtual VehicleVector getRivalVehicles(int linkIndex)
return vehicles that approach the intersection/rail signal and are in conflict with vehicles that wis...
const std::string & getProgramID() const
Returns this tl-logic's id.
TrafficLightType getLogicType() const
Returns the type of the logic.
int getNumLinks() const
return the number of controlled link indices
virtual const Phases & getPhases() const =0
Returns the phases of this tls program.
const LaneVectorVector & getLaneVectors() const
Returns the list of lists of all lanes controlled by this tls.
const LinkVector & getLinksAt(int i) const
Returns the list of links that are controlled by the signals at the given position.
std::vector< LinkVector > LinkVectorVector
Definition of a list that holds lists of links that do have the same attribute.
std::vector< MSLink * > LinkVector
Definition of the list of links that are subjected to this tls.
virtual void init(NLDetectorBuilder &nb)
Initialises the tls with information about incoming lanes.
const MSLane * getLane() const
Returns the current lane (may be nullptr)
const MSEdge * getEdge() const
Returns the current edge.
The class responsible for building and deletion of vehicles.
SUMOVehicle * getVehicle(const std::string &id) const
Returns the vehicle with the given id.
std::map< std::string, SUMOVehicle * >::const_iterator constVehIt
Definition of the internal vehicles map iterator.
constVehIt loadedVehBegin() const
Returns the begin of the internal vehicle map.
constVehIt loadedVehEnd() const
Returns the end of the internal vehicle map.
A NEMA (adaptive) traffic light logic based on E2Detector.
Builds detectors for microsim.
const std::string & getID() const
Returns the id.
Definition: Named.h:74
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
const Parameterised::Map & getParametersMap() const
Returns the inner key/value map.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
virtual NumericalID getNumericalID() const =0
return the numerical ID which is only for internal usage
virtual const SUMOVehicleParameter & getParameter() const =0
Returns the vehicle's parameter (including departure definition)
virtual int getRoutePosition() const =0
return index of edge within route
virtual const MSEdge * getEdge() const =0
Returns the edge the object is currently at.
virtual double getPositionOnLane() const =0
Get the object's position along the lane.
Representation of a vehicle.
Definition: SUMOVehicle.h:60
virtual bool hasDeparted() const =0
Returns whether this vehicle has departed.
virtual const MSRoute & getRoute() const =0
Returns the current route.
bool wasSet(int what) const
Returns whether the given parameter was set.
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
C++ TraCI client API implementation.
static MSBaseVehicle * getVehicle(const std::string &id)
Definition: Helper.cpp:474
static MSTLLogicControl::TLSLogicVariants & getTLS(const std::string &id)
Definition: Helper.cpp:515
virtual std::string readString()
Definition: storage.cpp:180
virtual int readUnsignedByte()
Definition: storage.cpp:155
TRACI_CONST int VAR_NAME
TRACI_CONST int TRACI_ID_LIST
std::map< std::string, libsumo::SubscriptionResults > ContextSubscriptionResults
Definition: TraCIDefs.h:301
TRACI_CONST int TL_CONTROLLED_LANES
TRACI_CONST int TL_CONTROLLED_JUNCTIONS
std::map< std::string, libsumo::TraCIResults > SubscriptionResults
{object->{variable->value}}
Definition: TraCIDefs.h:300
TRACI_CONST int ID_COUNT
TRACI_CONST int VAR_PARAMETER
TRACI_CONST int TL_NEXT_SWITCH
TRACI_CONST int VAR_PARAMETER_WITH_KEY
TRACI_CONST int TL_PHASE_DURATION
TRACI_CONST int TL_CURRENT_PHASE
TRACI_CONST int TL_RED_YELLOW_GREEN_STATE
TRACI_CONST int TL_CURRENT_PROGRAM
std::string tripId
the tripId or vehicle id of the train that is constrained
Definition: TraCIDefs.h:616