Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/src/libsumo/TrafficLight.cpp
169665 views
1
/****************************************************************************/
2
// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
// Copyright (C) 2017-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 TrafficLight.cpp
15
/// @author Daniel Krajzewicz
16
/// @author Mario Krumnow
17
/// @author Jakob Erdmann
18
/// @author Michael Behrisch
19
/// @date 30.05.2012
20
///
21
// C++ TraCI client API implementation
22
/****************************************************************************/
23
#include <config.h>
24
25
#include <utils/common/StringUtils.h>
26
#include <microsim/MSLane.h>
27
#include <microsim/MSEdge.h>
28
#include <microsim/MSNet.h>
29
#include <microsim/MSVehicleControl.h>
30
#include <microsim/MSStop.h>
31
#include <microsim/transportables/MSTransportable.h>
32
#include <microsim/transportables/MSPerson.h>
33
#include <microsim/traffic_lights/MSTLLogicControl.h>
34
#include <microsim/traffic_lights/MSSimpleTrafficLightLogic.h>
35
#include <microsim/traffic_lights/MSActuatedTrafficLightLogic.h>
36
#include <microsim/traffic_lights/MSDelayBasedTrafficLightLogic.h>
37
#include "microsim/traffic_lights/NEMAController.h"
38
#include <microsim/traffic_lights/MSRailSignal.h>
39
#include <microsim/traffic_lights/MSRailSignalConstraint.h>
40
#include <microsim/traffic_lights/MSRailSignalControl.h>
41
#include <netload/NLDetectorBuilder.h>
42
#include <libsumo/TraCIConstants.h>
43
#include <libsumo/StorageHelper.h>
44
#include "Helper.h"
45
#include "TrafficLight.h"
46
47
//#define DEBUG_CONSTRAINT_DEADLOCK
48
49
namespace libsumo {
50
// ===========================================================================
51
// static member initializations
52
// ===========================================================================
53
SubscriptionResults TrafficLight::mySubscriptionResults;
54
ContextSubscriptionResults TrafficLight::myContextSubscriptionResults;
55
56
// ===========================================================================
57
// static member definitions
58
// ===========================================================================
59
std::vector<std::string>
60
TrafficLight::getIDList() {
61
return MSNet::getInstance()->getTLSControl().getAllTLIds();
62
}
63
64
65
int
66
TrafficLight::getIDCount() {
67
return (int)getIDList().size();
68
}
69
70
71
std::string
72
TrafficLight::getRedYellowGreenState(const std::string& tlsID) {
73
return Helper::getTLS(tlsID).getActive()->getCurrentPhaseDef().getState();
74
}
75
76
77
std::vector<TraCILogic>
78
TrafficLight::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
95
std::vector<std::string>
96
TrafficLight::getControlledJunctions(const std::string& tlsID) {
97
std::set<std::string> junctionIDs;
98
const MSTrafficLightLogic::LinkVectorVector& links = Helper::getTLS(tlsID).getActive()->getLinks();
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
108
std::vector<std::string>
109
TrafficLight::getControlledLanes(const std::string& tlsID) {
110
std::vector<std::string> laneIDs;
111
const MSTrafficLightLogic::LaneVectorVector& lanes = Helper::getTLS(tlsID).getActive()->getLaneVectors();
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
121
std::vector<std::vector<TraCILink> >
122
TrafficLight::getControlledLinks(const std::string& tlsID) {
123
std::vector<std::vector<TraCILink> > result;
124
const MSTrafficLightLogic::LaneVectorVector& lanes = Helper::getTLS(tlsID).getActive()->getLaneVectors();
125
const MSTrafficLightLogic::LinkVectorVector& links = Helper::getTLS(tlsID).getActive()->getLinks();
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
145
std::string
146
TrafficLight::getProgram(const std::string& tlsID) {
147
return Helper::getTLS(tlsID).getActive()->getProgramID();
148
}
149
150
151
int
152
TrafficLight::getPhase(const std::string& tlsID) {
153
return Helper::getTLS(tlsID).getActive()->getCurrentPhaseIndex();
154
}
155
156
157
std::string
158
TrafficLight::getPhaseName(const std::string& tlsID) {
159
return Helper::getTLS(tlsID).getActive()->getCurrentPhaseDef().getName();
160
}
161
162
163
double
164
TrafficLight::getPhaseDuration(const std::string& tlsID) {
165
return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getCurrentPhaseDef().duration);
166
}
167
168
169
double
170
TrafficLight::getNextSwitch(const std::string& tlsID) {
171
return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getNextSwitchTime());
172
}
173
174
175
double
176
TrafficLight::getSpentDuration(const std::string& tlsID) {
177
return STEPS2TIME(Helper::getTLS(tlsID).getActive()->getSpentDuration());
178
}
179
180
int
181
TrafficLight::getServedPersonCount(const std::string& tlsID, int index) {
182
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
183
if (index < 0 || active->getPhaseNumber() <= index) {
184
throw TraCIException("The phase index " + toString(index) + " is not in the allowed range [0,"
185
+ toString(active->getPhaseNumber() - 1) + "].");
186
}
187
// find all crossings which have a green light in that phas
188
int result = 0;
189
190
const std::string& state = active->getPhases()[index]->getState();
191
for (int i = 0; i < (int)state.size(); i++) {
192
if (state[i] == LINKSTATE_TL_GREEN_MAJOR) {
193
for (MSLink* link : active->getLinksAt(i)) {
194
if (link->getLane()->getEdge().isCrossing()) {
195
// walking forwards across
196
for (MSTransportable* person : link->getLaneBefore()->getEdge().getPersons()) {
197
if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLane()->getEdge().getID()) {
198
result += 1;
199
}
200
}
201
// walking backwards across
202
MSLane* walkingAreaAcross = link->getLane()->getLinkCont().front()->getLane();
203
for (MSTransportable* person : walkingAreaAcross->getEdge().getPersons()) {
204
if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLane()->getEdge().getID()) {
205
result += 1;
206
}
207
}
208
} else if (link->getLaneBefore()->getEdge().isCrossing()) {
209
// walking backwards across (in case both sides are separately controlled)
210
for (MSTransportable* person : link->getLane()->getEdge().getPersons()) {
211
if (static_cast<MSPerson*>(person)->getNextEdge() == link->getLaneBefore()->getEdge().getID()) {
212
result += 1;
213
}
214
}
215
}
216
}
217
}
218
}
219
return result;
220
}
221
222
std::vector<std::string>
223
TrafficLight::getBlockingVehicles(const std::string& tlsID, int linkIndex) {
224
std::vector<std::string> result;
225
// for railsignals we cannot use the "online" program
226
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
227
if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
228
throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
229
+ toString(active->getNumLinks() - 1) + "].");
230
}
231
for (const SUMOVehicle* veh : active->getBlockingVehicles(linkIndex)) {
232
result.push_back(veh->getID());
233
}
234
return result;
235
}
236
237
std::vector<std::string>
238
TrafficLight::getRivalVehicles(const std::string& tlsID, int linkIndex) {
239
std::vector<std::string> result;
240
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
241
if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
242
throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
243
+ toString(active->getNumLinks() - 1) + "].");
244
}
245
for (const SUMOVehicle* veh : active->getRivalVehicles(linkIndex)) {
246
result.push_back(veh->getID());
247
}
248
return result;
249
}
250
251
std::vector<std::string>
252
TrafficLight::getPriorityVehicles(const std::string& tlsID, int linkIndex) {
253
std::vector<std::string> result;
254
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
255
if (linkIndex < 0 || linkIndex >= active->getNumLinks()) {
256
throw TraCIException("The link index " + toString(linkIndex) + " is not in the allowed range [0,"
257
+ toString(active->getNumLinks() - 1) + "].");
258
}
259
for (const SUMOVehicle* veh : active->getPriorityVehicles(linkIndex)) {
260
result.push_back(veh->getID());
261
}
262
return result;
263
}
264
265
std::vector<TraCISignalConstraint>
266
TrafficLight::getConstraints(const std::string& tlsID, const std::string& tripId) {
267
std::vector<TraCISignalConstraint> result;
268
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
269
MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
270
if (s == nullptr) {
271
throw TraCIException("'" + tlsID + "' is not a rail signal");
272
}
273
for (auto item : s->getConstraints()) {
274
if (tripId != "" && tripId != item.first) {
275
continue;
276
}
277
for (MSRailSignalConstraint* c : item.second) {
278
result.push_back(buildConstraint(tlsID, item.first, c));
279
}
280
}
281
return result;
282
}
283
284
std::vector<TraCISignalConstraint>
285
TrafficLight::getConstraintsByFoe(const std::string& foeSignal, const std::string& foeId) {
286
// retrieve all constraints that have the given foeSignal (optionally filtered by foeId)
287
// @note could improve efficiency by storing a map of rail signals in MSRailSignalControl
288
std::vector<TraCISignalConstraint> result;
289
for (const std::string& tlsID : getIDList()) {
290
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
291
MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
292
if (s != nullptr) {
293
for (auto item : s->getConstraints()) {
294
for (MSRailSignalConstraint* cand : item.second) {
295
MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
296
if (pc != nullptr && pc->myFoeSignal->getID() == foeSignal
297
&& (foeId == "" || pc->myTripId == foeId)) {
298
result.push_back(buildConstraint(s->getID(), item.first, pc));
299
}
300
}
301
}
302
}
303
}
304
return result;
305
}
306
307
308
void
309
TrafficLight::addConstraint(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId, const int type, const int limit) {
310
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
311
MSTrafficLightLogic* const active2 = Helper::getTLS(foeSignal).getDefault();
312
MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
313
MSRailSignal* s2 = dynamic_cast<MSRailSignal*>(active2);
314
if (s == nullptr) {
315
throw TraCIException("'" + tlsID + "' is not a rail signal");
316
}
317
if (s2 == nullptr) {
318
throw TraCIException("'" + foeSignal + "' is not a rail signal");
319
}
320
MSRailSignalConstraint* c = new MSRailSignalConstraint_Predecessor((MSRailSignalConstraint::ConstraintType)type, s2, foeId, limit, true);
321
s->addConstraint(tripId, c);
322
}
323
324
325
std::vector<TraCISignalConstraint>
326
TrafficLight::swapConstraints(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId) {
327
#ifdef DEBUG_CONSTRAINT_DEADLOCK
328
std::cout << "swapConstraints tlsId=" << tlsID << " tripId=" << tripId << " foeSignal=" << foeSignal << " foeId=" << foeId << "\n";
329
#endif
330
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getDefault();
331
MSTrafficLightLogic* const active2 = Helper::getTLS(foeSignal).getDefault();
332
MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
333
MSRailSignal* s2 = dynamic_cast<MSRailSignal*>(active2);
334
if (s == nullptr) {
335
throw TraCIException("'" + tlsID + "' is not a rail signal");
336
}
337
if (s2 == nullptr) {
338
throw TraCIException("'" + foeSignal + "' is not a rail signal");
339
}
340
MSRailSignalConstraint_Predecessor* c = nullptr;
341
for (auto item : s->getConstraints()) {
342
if (tripId == item.first) {
343
for (MSRailSignalConstraint* cand : item.second) {
344
MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
345
if (pc != nullptr && pc->myFoeSignal->getID() == foeSignal && pc->myTripId == foeId) {
346
c = pc;
347
break;
348
}
349
}
350
break;
351
}
352
}
353
if (c != nullptr) {
354
const int limit = c->myLimit;
355
// the two constraints are complementary so we actually remove rather than deactivate to avoid redundant conflict information
356
MSRailSignalConstraint::ConstraintType type = c->getSwappedType();
357
MSRailSignalConstraint* swapped = new MSRailSignalConstraint_Predecessor(type, s, tripId, limit, true);
358
swapped->updateParameters(c->getParametersMap());
359
swapParameters(swapped);
360
s->removeConstraint(tripId, c);
361
s2->addConstraint(foeId, swapped);
362
return findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
363
} else {
364
throw TraCIException("Rail signal '" + tlsID + "' does not have a constraint for tripId '" + tripId + "' with foeSignal '" + foeSignal + "' and foeId '" + foeId + "'");
365
}
366
}
367
368
369
std::vector<std::pair<std::string, std::string> >
370
TrafficLight::getSwapParams(int constraintType) {
371
std::vector<std::pair<std::string, std::string> > result({
372
{"vehID", "foeID"},
373
{"line", "foeLine"},
374
{"arrival", "foeArrival"}});
375
376
if (constraintType == MSRailSignalConstraint::ConstraintType::BIDI_PREDECESSOR) {
377
std::vector<std::pair<std::string, std::string> > special({
378
{"busStop", "busStop2"},
379
{"priorStop", "priorStop2"},
380
{"stopArrival", "foeStopArrival"}});
381
result.insert(result.end(), special.begin(), special.end());
382
}
383
return result;
384
}
385
386
387
void
388
TrafficLight::swapParameters(MSRailSignalConstraint* c) {
389
// swap parameters that were assigned by generateRailSignalConstraints.py
390
for (auto keys : getSwapParams(c->getType())) {
391
swapParameters(c, keys.first, keys.second);
392
}
393
}
394
395
void
396
TrafficLight::swapParameters(MSRailSignalConstraint* c, const std::string& key1, const std::string& key2) {
397
const std::string value1 = c->getParameter(key1);
398
const std::string value2 = c->getParameter(key2);
399
if (value1 != "") {
400
c->setParameter(key2, value1);
401
} else {
402
c->unsetParameter(key2);
403
}
404
if (value2 != "") {
405
c->setParameter(key1, value2);
406
} else {
407
c->unsetParameter(key1);
408
}
409
}
410
411
void
412
TrafficLight::swapParameters(TraCISignalConstraint& c) {
413
// swap parameters that were assigned by generateRailSignalConstraints.py
414
for (auto keys : getSwapParams(c.type)) {
415
swapParameters(c, keys.first, keys.second);
416
}
417
}
418
419
void
420
TrafficLight::swapParameters(TraCISignalConstraint& c, const std::string& key1, const std::string& key2) {
421
auto it1 = c.param.find(key1);
422
auto it2 = c.param.find(key2);
423
const std::string value1 = it1 != c.param.end() ? it1->second : "";
424
const std::string value2 = it2 != c.param.end() ? it2->second : "";
425
if (value1 != "") {
426
c.param[key2] = value1;
427
} else {
428
c.param.erase(key2);
429
}
430
if (value2 != "") {
431
c.param[key1] = value2;
432
} else {
433
c.param.erase(key1);
434
}
435
}
436
437
438
void
439
TrafficLight::removeConstraints(const std::string& tlsID, const std::string& tripId, const std::string& foeSignal, const std::string& foeId) {
440
// remove all constraints that have the given foeId
441
// @note could improve efficiency by storing a map of rail signals in MSRailSignalControl
442
for (const std::string& tlsCand : getIDList()) {
443
if (tlsID == "" || tlsCand == tlsID) {
444
MSTrafficLightLogic* const active = Helper::getTLS(tlsCand).getDefault();
445
MSRailSignal* s = dynamic_cast<MSRailSignal*>(active);
446
if (s != nullptr) {
447
for (auto item : s->getConstraints()) {
448
if (tripId == "" || item.first == tripId) {
449
for (MSRailSignalConstraint* cand : item.second) {
450
MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
451
if (pc != nullptr
452
&& (foeId == "" || pc->myTripId == foeId)
453
&& (foeSignal == "" || pc->myFoeSignal->getID() == foeSignal)) {
454
cand->setActive(false);
455
}
456
}
457
}
458
}
459
}
460
}
461
}
462
}
463
464
465
void
466
TrafficLight::updateConstraints(const std::string& vehID, std::string tripId) {
467
// Removes all constraints that can no longer be met because the route of
468
// vehID does not pass the signal involved in the constraint with the given tripId.
469
// This includes constraints on tripId as well as constraints where tripId is the foeId.
470
471
MSBaseVehicle* veh = Helper::getVehicle(vehID);
472
std::string curTripId = veh->getParameter().getParameter("tripId", veh->getID());
473
tripId = tripId == "" ? curTripId : tripId;
474
475
// find signals and tripId along the route of veh
476
std::map<const MSRailSignal*, std::set<std::string> > onRoute;
477
const ConstMSEdgeVector& route = veh->getRoute().getEdges();
478
auto routeIt = veh->getCurrentRouteEdge();
479
for (const MSStop& stop : veh->getStops()) {
480
for (auto it = routeIt; it < stop.edge; it++) {
481
const MSEdge* edge = *it;
482
if (edge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
483
if (it + 1 != route.end()) {
484
const MSEdge* next = *(it + 1);
485
const MSLink* link = edge->getLanes()[0]->getLinkTo(next->getLanes()[0]);
486
if (link != nullptr && link->getTLLogic() != nullptr) {
487
const MSRailSignal* s = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
488
onRoute[s].insert(curTripId);
489
}
490
}
491
}
492
}
493
if (stop.pars.tripId != "") {
494
curTripId = stop.pars.tripId;
495
}
496
routeIt = stop.edge;
497
}
498
for (auto it = routeIt; it < route.end(); it++) {
499
const MSEdge* edge = *it;
500
if (edge->getToJunction()->getType() == SumoXMLNodeType::RAIL_SIGNAL) {
501
if (it + 1 != route.end()) {
502
const MSEdge* next = *(it + 1);
503
const MSLink* link = edge->getLanes()[0]->getLinkTo(next->getLanes()[0]);
504
if (link != nullptr && link->getTLLogic() != nullptr) {
505
const MSRailSignal* s = dynamic_cast<const MSRailSignal*>(link->getTLLogic());
506
onRoute[s].insert(curTripId);
507
}
508
}
509
}
510
}
511
//for (auto item : onRoute) {
512
// std::cout << " s=" << item.first->getID() << " @" << item.first << " ids=" << toString(item.second) << "\n";
513
//}
514
515
// check relevance for all active contraints
516
for (MSRailSignal* s : MSRailSignalControl::getInstance().getSignals()) {
517
518
// record outdated constraints on and by the vehicle
519
std::vector<MSRailSignalConstraint*> onVeh;
520
std::vector<std::pair<std::string, MSRailSignalConstraint*> > byVeh;
521
522
for (auto item : s->getConstraints()) {
523
for (MSRailSignalConstraint* cand : item.second) {
524
MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
525
if (pc != nullptr && !pc->cleared() && pc->isActive()) {
526
if (item.first == tripId) {
527
if (onRoute[s].count(tripId) == 0) {
528
// constraint on our veh no longer relevant
529
onVeh.push_back(cand);
530
}
531
} else if (pc->myTripId == tripId) {
532
if (onRoute[pc->myFoeSignal].count(tripId) == 0) {
533
// constraint by our veh no longer relevant
534
byVeh.push_back(std::make_pair(item.first, cand));
535
}
536
}
537
}
538
}
539
}
540
for (MSRailSignalConstraint* c : onVeh) {
541
s->removeConstraint(tripId, c);
542
}
543
for (auto item : byVeh) {
544
s->removeConstraint(item.first, item.second);
545
}
546
}
547
}
548
549
550
std::vector<TraCISignalConstraint>
551
TrafficLight::findConstraintsDeadLocks(const std::string& foeId, const std::string& tripId, const std::string& foeSignal, const std::string& tlsID) {
552
std::vector<TraCISignalConstraint> result;
553
// find circular constraints (deadlock)
554
// foeId is now constrainted by tripId and assumed to follow tripId on the
555
// same track without possibility of overtaking
556
// we look for a third vehicle foeId2 where
557
// tripId waits for foeId2 and foeId2 waits on foeId
558
std::map<std::string, TraCISignalConstraint> constraintsOnTripId;
559
std::map<std::string, TraCISignalConstraint> constrainedByFoeId;
560
std::set<std::string> foeId2Cands1;
561
std::set<std::string> foeId2Cands2;
562
for (MSRailSignal* s : MSRailSignalControl::getInstance().getSignals()) {
563
for (auto item : s->getConstraints()) {
564
for (MSRailSignalConstraint* cand : item.second) {
565
MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(cand);
566
if (pc != nullptr && !pc->cleared() && pc->isActive()) {
567
if (item.first == tripId) {
568
// tripId waits for foe2
569
// @could there by more than one constraint on tripId by this foe2?
570
libsumo::TraCISignalConstraint tsc = buildConstraint(s->getID(), item.first, pc);
571
constraintsOnTripId[pc->myTripId] = tsc;
572
foeId2Cands1.insert(pc->myTripId);
573
for (std::string& futureFoe2Id : getFutureTripIds(pc->myTripId)) {
574
foeId2Cands1.insert(futureFoe2Id);
575
//tsc.foeId = futureFoe2Id; // if we do this, the constraint to swap will not be found
576
constraintsOnTripId[futureFoe2Id] = tsc;
577
}
578
} else if (pc->myTripId == foeId) {
579
// foeId2 waits for foe
580
libsumo::TraCISignalConstraint tsc = buildConstraint(s->getID(), item.first, pc);
581
constrainedByFoeId[item.first] = tsc;
582
foeId2Cands2.insert(item.first);
583
for (std::string& futureTripId : getFutureTripIds(item.first)) {
584
foeId2Cands2.insert(futureTripId);
585
//tsc.tripId = futureTripId; // if we do this, the constraint to swap will not be found
586
constrainedByFoeId[futureTripId] = tsc;
587
}
588
}
589
}
590
}
591
}
592
}
593
#ifdef DEBUG_CONSTRAINT_DEADLOCK
594
std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << " tlsID=" << tlsID << "\n";
595
std::cout << " foeId2Cands1=" << toString(foeId2Cands1) << "\n";
596
std::cout << " foeId2Cands2=" << toString(foeId2Cands2) << "\n";
597
#endif
598
if (foeId2Cands1.size() > 0) {
599
// foe2 might be constrained implicitly by foe due to following on the same track
600
// in this case foe must be on the route of foe2 between its current position and foeSignal
601
602
// we have to check this first because it also affects foeInsertion
603
// constraints if the foe is already inserted but hasn't yet passed the
604
// signal (cleared == false).
605
SUMOVehicle* foe = getVehicleByTripId(foeId);
606
if (foe != nullptr) {
607
const MSEdge* foeEdge = foe->getEdge();
608
const double foePos = foe->getPositionOnLane();
609
for (const std::string& foeId2 : foeId2Cands1) {
610
// tripId waits for foeId2
611
SUMOVehicle* foe2 = getVehicleByTripId(foeId2);
612
if (foe2 != nullptr) {
613
const ConstMSEdgeVector& foe2Route = foe2->getRoute().getEdges();
614
const TraCISignalConstraint& c = constraintsOnTripId[foeId2];
615
bool foeAhead = false;
616
for (int i = foe2->getRoutePosition(); i < (int)foe2Route.size(); i++) {
617
const MSEdge* e = foe2Route[i];
618
if (e == foeEdge &&
619
((e != foe2->getEdge() || foe2->getPositionOnLane() < foePos)
620
|| (foe->hasDeparted() && !foe2->hasDeparted())
621
|| (!foe->hasDeparted() && !foe2->hasDeparted() &&
622
(foe->getParameter().depart < foe2->getParameter().depart
623
|| (foe->getParameter().depart == foe2->getParameter().depart && foe->getNumericalID() < foe2->getNumericalID())))
624
)) {
625
foeAhead = true;
626
#ifdef DEBUG_CONSTRAINT_DEADLOCK
627
std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
628
std::cout << " foeLeaderDeadlock foeEdge=" << foeEdge->getID() << " foe2=" << foe2->getParameter().getParameter("tripId", foe2->getID())
629
<< " routePos=" << foe2->getRoutePosition() << " futureRPos=" << i << " e=" << e->getID()
630
//<< " foePos=" << foePos << " foe2Pos=" << foe2->getPositionOnLane()
631
<< " " << constraintsOnTripId[foeId2].getString() << "\n";
632
#endif
633
break;
634
}
635
if (e->getToJunction()->getID() == foeSignal
636
|| e->getToJunction()->getID() == c.foeSignal) {
637
break;
638
}
639
}
640
if (foeAhead) {
641
// foe cannot wait for foe2 (since it's behind). Instead foe2 must wait for tripId
642
TraCISignalConstraint nc; // constraint after swap
643
nc.tripId = c.foeId;
644
nc.foeId = c.tripId;
645
nc.signalId = c.foeSignal;
646
nc.foeSignal = c.signalId;
647
nc.limit = c.limit;
648
nc.type = c.type;
649
nc.mustWait = true; // ???
650
nc.active = true;
651
nc.param = c.param;
652
swapParameters(nc);
653
result.push_back(nc);
654
// let foe wait for foe2
655
std::vector<TraCISignalConstraint> result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
656
result.insert(result.end(), result2.begin(), result2.end());
657
658
// Other deadlocks might not be valid anymore so we need a fresh recheck for remaining implicit or explicit deadlocks
659
const std::vector<TraCISignalConstraint>& result4 = findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
660
result.insert(result.end(), result4.begin(), result4.end());
661
return result;
662
}
663
}
664
}
665
}
666
}
667
668
if (foeId2Cands2.size() > 0) {
669
// tripId might be constrained implicitly by foe2 due to following on the same track
670
// in this case foe2 must be on the route of tripId between its current position and tlsID
671
// if foe2 then waits for foe, deadlock occurs
672
673
SUMOVehicle* ego = getVehicleByTripId(tripId);
674
if (ego != nullptr && (ego->hasDeparted() || !ego->getParameter().wasSet(VEHPARS_FORCE_REROUTE))) {
675
std::set<const MSEdge*> egoToSignal;
676
const double egoPos = ego->getPositionOnLane();
677
const ConstMSEdgeVector& egoRoute = ego->getRoute().getEdges();
678
for (int i = ego->getRoutePosition(); i < (int)egoRoute.size(); i++) {
679
const MSEdge* e = egoRoute[i];
680
egoToSignal.insert(e);
681
if (e->getToJunction()->getID() == tlsID) {
682
break;
683
}
684
}
685
686
for (const std::string& foeId2 : foeId2Cands2) {
687
// foeId2 waits for foe
688
SUMOVehicle* foe2 = getVehicleByTripId(foeId2);
689
//std::cout << " foe2=" << foe2->getID() << " edge=" << foe2->getEdge()->getID() << " egoToSignal=" << toString(egoToSignal) << "\n";
690
if (foe2 != nullptr) {
691
if (egoToSignal.count(foe2->getEdge()) != 0
692
&& (foe2->getEdge() != ego->getEdge() || foe2->getPositionOnLane() > egoPos)) {
693
const TraCISignalConstraint& c = constrainedByFoeId[foeId2];
694
#ifdef DEBUG_CONSTRAINT_DEADLOCK
695
std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
696
std::cout << " egoLeaderDeadlock foe2Edge=" << foe2->getEdge()->getID() << " foe2=" << foe2->getParameter().getParameter("tripId", foe2->getID())
697
<< " " << c.getString() << "\n";
698
#endif
699
// foe is already waiting for tripId (ego) and should also wait for foeId2
700
TraCISignalConstraint nc; // constraint after swap
701
nc.tripId = c.foeId;
702
nc.foeId = c.tripId;
703
nc.signalId = c.foeSignal;
704
nc.foeSignal = c.signalId;
705
nc.limit = c.limit;
706
nc.type = c.type;
707
nc.mustWait = true; // ???
708
nc.active = true;
709
nc.param = c.param;
710
swapParameters(nc);
711
result.push_back(nc);
712
// let foe wait for foe2
713
std::vector<TraCISignalConstraint> result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
714
result.insert(result.end(), result2.begin(), result2.end());
715
716
// Other deadlocks might not be valid anymore so we need a fresh recheck for remaining implicit or explicit deadlocks
717
const std::vector<TraCISignalConstraint>& result4 = findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
718
result.insert(result.end(), result4.begin(), result4.end());
719
return result;
720
}
721
}
722
}
723
} else if (ego != nullptr) {
724
WRITE_WARNINGF(TL("Cannot check for all deadlocks on swapConstraints because the route for vehicle '%' is not computed yet"), ego->getID());
725
}
726
}
727
728
// find deadlock in explicit constraints
729
std::vector<std::string> foeIds2;
730
std::set_intersection(
731
foeId2Cands1.begin(), foeId2Cands1.end(),
732
foeId2Cands2.begin(), foeId2Cands2.end(),
733
std::back_inserter(foeIds2));
734
#ifdef DEBUG_CONSTRAINT_DEADLOCK
735
std::cout << "findConstraintsDeadLocks foeId=" << foeId << " tripId=" << tripId << " foeSignal=" << foeSignal << "\n";
736
for (const std::string& foeId2 : foeIds2) {
737
std::cout << " deadlockId=" << foeId2 << " " << constraintsOnTripId[foeId2].getString() << " " << constrainedByFoeId[foeId2].getString() << "\n";
738
}
739
#endif
740
if (foeIds2.size() > 0) {
741
TraCISignalConstraint c = constrainedByFoeId[foeIds2.front()];
742
if (c.type == MSRailSignalConstraint::ConstraintType::INSERTION_PREDECESSOR) {
743
// avoid swapping insertion constraint
744
c = constraintsOnTripId[foeIds2.front()];
745
}
746
TraCISignalConstraint nc; // constraint after swap
747
nc.tripId = c.foeId;
748
nc.foeId = c.tripId;
749
nc.signalId = c.foeSignal;
750
nc.foeSignal = c.signalId;
751
nc.limit = c.limit;
752
nc.type = c.type;
753
nc.mustWait = true; // ???
754
nc.active = true;
755
nc.param = c.param;
756
swapParameters(nc);
757
result.push_back(nc);
758
// let foe wait for foe2
759
const std::vector<TraCISignalConstraint>& result2 = swapConstraints(c.signalId, c.tripId, c.foeSignal, c.foeId);
760
result.insert(result.end(), result2.begin(), result2.end());
761
if (foeIds2.size() > 1) {
762
// calling swapConstraints once may result in further swaps so we have to recheck for remaining deadlocks anew
763
const std::vector<TraCISignalConstraint>& result3 = findConstraintsDeadLocks(foeId, tripId, foeSignal, tlsID);
764
result.insert(result.end(), result3.begin(), result3.end());
765
}
766
}
767
return result;
768
}
769
770
771
SUMOVehicle*
772
TrafficLight::getVehicleByTripId(const std::string tripOrVehID) {
773
MSVehicleControl& c = MSNet::getInstance()->getVehicleControl();
774
for (MSVehicleControl::constVehIt i = c.loadedVehBegin(); i != c.loadedVehEnd(); ++i) {
775
SUMOVehicle* veh = i->second;
776
if (veh->getParameter().getParameter("tripId", veh->getID()) == tripOrVehID) {
777
return veh;
778
}
779
}
780
return nullptr;
781
}
782
783
784
std::vector<std::string>
785
TrafficLight::getFutureTripIds(const std::string vehID) {
786
std::vector<std::string> result;
787
MSBaseVehicle* veh = dynamic_cast<MSBaseVehicle*>(MSNet::getInstance()->getVehicleControl().getVehicle(vehID));
788
if (veh) {
789
std::string tripId = veh->getParameter().getParameter("tripId");
790
if (tripId != "") {
791
result.push_back(tripId);
792
}
793
for (const MSStop& stop : veh->getStops()) {
794
if (stop.pars.tripId != "") {
795
result.push_back(stop.pars.tripId);
796
}
797
}
798
}
799
return result;
800
}
801
802
803
std::string
804
TrafficLight::getParameter(const std::string& tlsID, const std::string& paramName) {
805
MSTrafficLightLogic* tll = Helper::getTLS(tlsID).getActive();
806
if (StringUtils::startsWith(paramName, "NEMA.") && tll->getLogicType() != TrafficLightType::NEMA) {
807
throw TraCIException("'" + tlsID + "' is not a NEMA controller");
808
}
809
return tll->getParameter(paramName, "");
810
}
811
812
813
LIBSUMO_GET_PARAMETER_WITH_KEY_IMPLEMENTATION(TrafficLight)
814
815
816
void
817
TrafficLight::setRedYellowGreenState(const std::string& tlsID, const std::string& state) {
818
Helper::getTLS(tlsID).setStateInstantiatingOnline(MSNet::getInstance()->getTLSControl(), state);
819
}
820
821
822
void
823
TrafficLight::setPhase(const std::string& tlsID, const int index) {
824
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
825
if (index < 0 || active->getPhaseNumber() <= index) {
826
throw TraCIException("The phase index " + toString(index) + " is not in the allowed range [0,"
827
+ toString(active->getPhaseNumber() - 1) + "].");
828
}
829
const SUMOTime cTime = MSNet::getInstance()->getCurrentTimeStep();
830
const SUMOTime duration = active->getPhase(index).duration;
831
active->changeStepAndDuration(MSNet::getInstance()->getTLSControl(), cTime, index, duration);
832
}
833
834
void
835
TrafficLight::setPhaseName(const std::string& tlsID, const std::string& name) {
836
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
837
const_cast<MSPhaseDefinition&>(active->getCurrentPhaseDef()).setName(name);
838
}
839
840
841
void
842
TrafficLight::setProgram(const std::string& tlsID, const std::string& programID) {
843
try {
844
Helper::getTLS(tlsID).switchTo(MSNet::getInstance()->getTLSControl(), programID);
845
} catch (ProcessError& e) {
846
throw TraCIException(e.what());
847
}
848
}
849
850
851
void
852
TrafficLight::setPhaseDuration(const std::string& tlsID, const double phaseDuration) {
853
MSTrafficLightLogic* const active = Helper::getTLS(tlsID).getActive();
854
const SUMOTime cTime = MSNet::getInstance()->getCurrentTimeStep();
855
active->changeStepAndDuration(MSNet::getInstance()->getTLSControl(), cTime, -1, TIME2STEPS(phaseDuration));
856
}
857
858
859
void
860
TrafficLight::setProgramLogic(const std::string& tlsID, const TraCILogic& logic) {
861
MSTLLogicControl::TLSLogicVariants& vars = Helper::getTLS(tlsID);
862
// make sure index and phaseNo are consistent
863
if (logic.currentPhaseIndex >= (int)logic.phases.size()) {
864
throw TraCIException("set program: parameter index must be less than parameter phase number.");
865
}
866
std::vector<MSPhaseDefinition*> phases;
867
for (const std::shared_ptr<libsumo::TraCIPhase>& phase : logic.phases) {
868
MSPhaseDefinition* sumoPhase = new MSPhaseDefinition(TIME2STEPS(phase->duration), phase->state, phase->name);
869
sumoPhase->minDuration = TIME2STEPS(phase->minDur);
870
sumoPhase->maxDuration = TIME2STEPS(phase->maxDur);
871
sumoPhase->nextPhases = phase->next;
872
phases.push_back(sumoPhase);
873
}
874
if (vars.getLogic(logic.programID) == nullptr) {
875
MSTLLogicControl& tlc = MSNet::getInstance()->getTLSControl();
876
int step = logic.currentPhaseIndex;
877
const std::string basePath = "";
878
MSTrafficLightLogic* tlLogic = nullptr;
879
SUMOTime nextSwitch = MSNet::getInstance()->getCurrentTimeStep() + phases[0]->duration;
880
switch ((TrafficLightType)logic.type) {
881
case TrafficLightType::ACTUATED:
882
tlLogic = new MSActuatedTrafficLightLogic(tlc,
883
tlsID, logic.programID, 0,
884
phases, step, nextSwitch,
885
logic.subParameter, basePath);
886
break;
887
case TrafficLightType::NEMA:
888
tlLogic = new NEMALogic(tlc,
889
tlsID, logic.programID, 0,
890
phases, step, nextSwitch,
891
logic.subParameter, basePath);
892
break;
893
case TrafficLightType::DELAYBASED:
894
tlLogic = new MSDelayBasedTrafficLightLogic(tlc,
895
tlsID, logic.programID, 0,
896
phases, step, nextSwitch,
897
logic.subParameter, basePath);
898
break;
899
case TrafficLightType::STATIC:
900
tlLogic = new MSSimpleTrafficLightLogic(tlc,
901
tlsID, logic.programID, 0, TrafficLightType::STATIC,
902
phases, step, nextSwitch,
903
logic.subParameter);
904
break;
905
default:
906
throw TraCIException("Unsupported traffic light type '" + toString(logic.type) + "'");
907
}
908
try {
909
if (!vars.addLogic(logic.programID, tlLogic, true, true)) {
910
throw TraCIException("Could not add traffic light logic '" + logic.programID + "'");
911
}
912
} catch (const ProcessError& e) {
913
throw TraCIException(e.what());
914
}
915
// XXX pass GUIDetectorBuilder when running with gui
916
NLDetectorBuilder db(*MSNet::getInstance());
917
tlLogic->init(db);
918
MSNet::getInstance()->createTLWrapper(tlLogic);
919
} else {
920
MSSimpleTrafficLightLogic* tlLogic = static_cast<MSSimpleTrafficLightLogic*>(vars.getLogic(logic.programID));
921
tlLogic->setPhases(phases, logic.currentPhaseIndex);
922
tlLogic->setTrafficLightSignals(MSNet::getInstance()->getCurrentTimeStep());
923
vars.executeOnSwitchActions();
924
}
925
}
926
927
928
void
929
TrafficLight::setParameter(const std::string& tlsID, const std::string& paramName, const std::string& value) {
930
MSTrafficLightLogic* tll = Helper::getTLS(tlsID).getActive();
931
if (StringUtils::startsWith(paramName, "NEMA.") && tll->getLogicType() != TrafficLightType::NEMA) {
932
throw TraCIException("'" + tlsID + "' is not a NEMA controller");
933
}
934
tll->setParameter(paramName, value);
935
}
936
937
LIBSUMO_SUBSCRIPTION_IMPLEMENTATION(TrafficLight, TL)
938
939
void
940
TrafficLight::setNemaSplits(const std::string& tlsID, const std::vector<double>& splits) {
941
setParameter(tlsID, "NEMA.splits", toString(splits));
942
}
943
944
void
945
TrafficLight::setNemaMaxGreens(const std::string& tlsID, const std::vector<double>& maxGreens) {
946
setParameter(tlsID, "NEMA.maxGreens", toString(maxGreens));
947
}
948
949
void
950
TrafficLight::setNemaCycleLength(const std::string& tlsID, double cycleLength) {
951
setParameter(tlsID, "NEMA.cycleLength", toString(cycleLength));
952
}
953
954
void
955
TrafficLight::setNemaOffset(const std::string& tlsID, double offset) {
956
setParameter(tlsID, "NEMA.offset", toString(offset));
957
}
958
959
960
libsumo::TraCISignalConstraint
961
TrafficLight::buildConstraint(const std::string& tlsID, const std::string& tripId, MSRailSignalConstraint* constraint) {
962
TraCISignalConstraint c;
963
c.tripId = tripId;
964
MSRailSignalConstraint_Predecessor* pc = dynamic_cast<MSRailSignalConstraint_Predecessor*>(constraint);
965
if (pc == nullptr) {
966
// unsupported constraint
967
c.type = -1;
968
} else {
969
c.signalId = tlsID;
970
c.foeId = pc->myTripId;
971
c.foeSignal = pc->myFoeSignal->getID();
972
c.limit = pc->myLimit;
973
c.type = pc->getType();
974
c.mustWait = !pc->cleared() && pc->isActive();
975
c.active = pc->isActive();
976
c.param = constraint->getParametersMap();
977
}
978
return c;
979
}
980
981
982
std::shared_ptr<VariableWrapper>
983
TrafficLight::makeWrapper() {
984
return std::make_shared<Helper::SubscriptionWrapper>(handleVariable, mySubscriptionResults, myContextSubscriptionResults);
985
}
986
987
988
bool
989
TrafficLight::handleVariable(const std::string& objID, const int variable, VariableWrapper* wrapper, tcpip::Storage* paramData) {
990
switch (variable) {
991
case TRACI_ID_LIST:
992
return wrapper->wrapStringList(objID, variable, getIDList());
993
case ID_COUNT:
994
return wrapper->wrapInt(objID, variable, getIDCount());
995
case TL_RED_YELLOW_GREEN_STATE:
996
return wrapper->wrapString(objID, variable, getRedYellowGreenState(objID));
997
case TL_COMPLETE_DEFINITION_RYG:
998
return wrapper->wrapLogicVector(objID, variable, getAllProgramLogics(objID));
999
case TL_CONTROLLED_LANES:
1000
return wrapper->wrapStringList(objID, variable, getControlledLanes(objID));
1001
case TL_CONTROLLED_LINKS:
1002
return wrapper->wrapLinkVectorVector(objID, variable, getControlledLinks(objID));
1003
case TL_CURRENT_PHASE:
1004
return wrapper->wrapInt(objID, variable, getPhase(objID));
1005
case VAR_NAME:
1006
return wrapper->wrapString(objID, variable, getPhaseName(objID));
1007
case TL_CURRENT_PROGRAM:
1008
return wrapper->wrapString(objID, variable, getProgram(objID));
1009
case TL_PHASE_DURATION:
1010
return wrapper->wrapDouble(objID, variable, getPhaseDuration(objID));
1011
case TL_NEXT_SWITCH:
1012
return wrapper->wrapDouble(objID, variable, getNextSwitch(objID));
1013
case TL_SPENT_DURATION:
1014
return wrapper->wrapDouble(objID, variable, getSpentDuration(objID));
1015
case VAR_PERSON_NUMBER:
1016
return wrapper->wrapInt(objID, variable, getServedPersonCount(objID, StoHelp::readTypedInt(*paramData)));
1017
case TL_BLOCKING_VEHICLES:
1018
return wrapper->wrapStringList(objID, variable, getBlockingVehicles(objID, StoHelp::readTypedInt(*paramData)));
1019
case TL_RIVAL_VEHICLES:
1020
return wrapper->wrapStringList(objID, variable, getRivalVehicles(objID, StoHelp::readTypedInt(*paramData)));
1021
case TL_PRIORITY_VEHICLES:
1022
return wrapper->wrapStringList(objID, variable, getPriorityVehicles(objID, StoHelp::readTypedInt(*paramData)));
1023
case TL_CONSTRAINT:
1024
return wrapper->wrapSignalConstraintVector(objID, variable, getConstraints(objID, StoHelp::readTypedString(*paramData)));
1025
case TL_CONSTRAINT_BYFOE:
1026
return wrapper->wrapSignalConstraintVector(objID, variable, getConstraintsByFoe(objID, StoHelp::readTypedString(*paramData)));
1027
case TL_CONTROLLED_JUNCTIONS:
1028
return wrapper->wrapStringList(objID, variable, getControlledJunctions(objID));
1029
case VAR_PARAMETER:
1030
return wrapper->wrapString(objID, variable, getParameter(objID, StoHelp::readTypedString(*paramData)));
1031
case VAR_PARAMETER_WITH_KEY:
1032
return wrapper->wrapStringPair(objID, variable, getParameterWithKey(objID, StoHelp::readTypedString(*paramData)));
1033
default:
1034
return false;
1035
}
1036
}
1037
}
1038
1039
1040
/****************************************************************************/
1041
1042