Eclipse SUMO - Simulation of Urban MObility
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
MSActuatedTrafficLightLogic.cpp
Go to the documentation of this file.
1/****************************************************************************/
2// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
22// An actuated (adaptive) traffic light logic
23/****************************************************************************/
24#include <config.h>
25
26#include <cassert>
27#include <utility>
28#include <vector>
29#include <bitset>
34#include <microsim/MSGlobals.h>
35#include <microsim/MSNet.h>
36#include <microsim/MSLane.h>
37#include <microsim/MSEdge.h>
41
42//#define DEBUG_DETECTORS
43//#define DEBUG_PHASE_SELECTION
44//#define DEBUG_PHASE_SELECTION_CUSTOM
45#define DEBUG_COND (getID()=="C")
46
47// ===========================================================================
48// static members
49// ===========================================================================
50const std::vector<std::string> MSActuatedTrafficLightLogic::OPERATOR_PRECEDENCE({
51 "**", "^", "*", "/", "+", "-", "%",
52 "=", "==", "!=", "<", ">", "<=", ">=",
53 "and", "&&", "or", "||",
54});
55
56// ===========================================================================
57// parameter defaults definitions
58// ===========================================================================
59#define DEFAULT_MAX_GAP "3.0"
60#define DEFAULT_PASSING_TIME "1.9"
61#define DEFAULT_DETECTOR_GAP "2.0"
62#define DEFAULT_INACTIVE_THRESHOLD "180"
63#define DEFAULT_CURRENT_PRIORITY 10
64#define DEFAULT_CROSSING_PRIORITY 100
65
66#define DEFAULT_LENGTH_WITH_GAP 7.5
67#define DEFAULT_BIKE_LENGTH_WITH_GAP (getDefaultVehicleLength(SVC_BICYCLE) + 0.5)
68#define DEFAULT_STATIC_MINDUR TIME2STEPS(0) // loop position for non-stretchable phases
69
70#define NO_DETECTOR "NO_DETECTOR"
71#define DEFAULT_CONDITION "DEFAULT"
72
73// ===========================================================================
74// method definitions
75// ===========================================================================
77 const std::string& id, const std::string& programID,
78 const SUMOTime offset,
79 const Phases& phases,
80 int step, SUMOTime delay,
81 const Parameterised::Map& parameter,
82 const std::string& basePath,
83 const ConditionMap& conditions,
84 const AssignmentMap& assignments,
85 const FunctionMap& functions) :
86 MSSimpleTrafficLightLogic(tlcontrol, id, programID, offset, TrafficLightType::ACTUATED, phases, step, delay, parameter),
87 myHasMultiTarget(false),
88 myLastTrySwitchTime(0),
89 myConditions(conditions),
90 myAssignments(assignments),
91 myFunctions(functions),
92 myTraCISwitch(false),
93 myDetectorPrefix(id + "_" + programID + "_") {
95 myJamThreshold = StringUtils::toDouble(getParameter("jam-threshold", OptionsCont::getOptions().getValueString("tls.actuated.jam-threshold")));
99 myShowDetectors = StringUtils::toBool(getParameter("show-detectors", toString(OptionsCont::getOptions().getBool("tls.actuated.show-detectors"))));
100 myBuildAllDetectors = StringUtils::toBool(getParameter("build-all-detectors", "false"));
101 myFile = FileHelpers::checkForRelativity(getParameter("file", "NUL"), basePath);
103 myVehicleTypes = getParameter("vTypes", "");
104
105 if (hasParameter("hide-conditions")) {
106 std::vector<std::string> hidden = StringTokenizer(getParameter("hide-conditions", "")).getVector();
107 std::set<std::string> hiddenSet(hidden.begin(), hidden.end());
108 for (auto item : myConditions) {
109 if (hiddenSet.count(item.first) == 0) {
110 myListedConditions.insert(item.first);
111 }
112 }
113 } else {
114 const bool showAll = getParameter("show-conditions", "") == "";
115 std::vector<std::string> shown = StringTokenizer(getParameter("show-conditions", "")).getVector();
116 std::set<std::string> shownSet(shown.begin(), shown.end());
117 for (auto item : myConditions) {
118 if (showAll || shownSet.count(item.first) != 0) {
119 myListedConditions.insert(item.first);
120 }
121 }
122 }
123 if (hasParameter("extra-detectors")) {
124 const std::string extraIDs = getParameter("extra-detectors", "");
125 for (std::string customID : StringTokenizer(extraIDs).getVector()) {
126 try {
127 myExtraLoops.push_back(retrieveDetExpression<MSInductLoop, SUMO_TAG_INDUCTION_LOOP>(customID, extraIDs, true));
128 } catch (ProcessError&) {
129 myExtraE2.push_back(retrieveDetExpression<MSE2Collector, SUMO_TAG_LANE_AREA_DETECTOR>(customID, extraIDs, true));
130 }
131 }
132 }
133 myStack.push_back(std::map<std::string, double>());
134}
135
136
138
139void
144 for (int i = 0; i < (int)myPhases.size(); i++) {
145 initTargets(i);
146 }
147 if (myLanes.size() == 0) {
148 // must be an older network
149 WRITE_WARNINGF(TL("Traffic light '%' does not control any links"), getID());
150 }
151 bool warn = true; // warn only once
152 const int numLinks = (int)myLinks.size();
153
154 // Detector position should be computed based on road speed. If the position
155 // is quite far away and the minDur is short this may cause the following
156 // problems:
157 //
158 // 1) high flow failure:
159 // In a standing queue, no vehicle touches the detector.
160 // By the time the queue advances, the detector gap has been exceeded and the phase terminates prematurely
161 //
162 // 2) low flow failure
163 // The standing queue is fully between stop line and detector and there are no further vehicles.
164 // The minDur is too short to let all vehicles pass
165 //
166 // Problem 2) is not so critical because there is less potential for
167 // jamming in a low-flow situation. In contrast, problem 1) should be
168 // avoided as it has big jamming potential. We compute an upper bound for the
169 // detector distance to avoid it
170
171
172 std::set<int> multiNextTargets = getMultiNextTargets();
173 // change values for setting the loops and lanestate-detectors, here
174 //SUMOTime inductLoopInterval = 1; //
175 // build the induct loops
176 std::map<const MSLane*, MSInductLoop*> laneInductLoopMap;
177 std::map<MSInductLoop*, int> inductLoopInfoMap; // retrieve junction entry lane in case loops are placed further upstream (and other properties)
178 int detEdgeIndex = -1;
179 int detLaneIndex = 0;
180 const double detDefaultLength = StringUtils::toDouble(getParameter("detector-length",
181 OptionsCont::getOptions().getValueString("tls.actuated.detector-length")));
182 MSEdge* prevDetEdge = nullptr;
183 for (LaneVector& lanes : myLanes) {
184 for (MSLane* lane : lanes) {
185 const std::string customID = getParameter(lane->getID());
186 if (noVehicles(lane->getPermissions()) && customID == "") {
187 // do not build detectors on green verges or sidewalks
188 continue;
189 }
190 if (laneInductLoopMap.find(lane) != laneInductLoopMap.end()) {
191 // only build one detector per lane
192 continue;
193 }
194 const SUMOTime minDur = getMinimumMinDuration(lane, multiNextTargets);
195 if (minDur == std::numeric_limits<SUMOTime>::max() && customID == "" && !myBuildAllDetectors) {
196 // only build detector if this lane is relevant for an actuated phase
197 continue;
198 }
199 double length = lane->getLength();
200 double ilpos;
201 double inductLoopPosition;
202 MSInductLoop* loop = nullptr;
203 if (&lane->getEdge() != prevDetEdge) {
204 detEdgeIndex++;
205 detLaneIndex = 0;
206 prevDetEdge = &lane->getEdge();
207 } else {
208 detLaneIndex++;
209 }
210 const bool isBikeLane = (lane->getPermissions() & ~SVC_PEDESTRIAN) == SVC_BICYCLE;
211 const double defaultLength = isBikeLane ? DEFAULT_BIKE_LENGTH_WITH_GAP : DEFAULT_LENGTH_WITH_GAP;
212 if (customID == "") {
213 const double speed = isBikeLane ? DEFAULT_BICYCLE_SPEED : lane->getSpeedLimit();
214 inductLoopPosition = MIN2(
215 myDetectorGap * speed,
216 (STEPS2TIME(minDur) / myPassingTime + 0.5) * defaultLength);
217
218 // check whether the lane is long enough
219 ilpos = length - inductLoopPosition;
220 MSLane* placementLane = lane;
221 while (ilpos < 0 && placementLane->getIncomingLanes().size() == 1
222 && placementLane->getIncomingLanes().front().viaLink->getCorrespondingEntryLink()->getTLLogic() == nullptr) {
223 placementLane = placementLane->getLogicalPredecessorLane();
224 ilpos += placementLane->getLength();
225 }
226 if (ilpos < 0) {
227 ilpos = 0;
228 }
229 // Build the induct loop and set it into the container
230 const double detLength = getDouble("detector-length:" + lane->getID(), detDefaultLength);
231 std::string id = myDetectorPrefix + "D" + toString(detEdgeIndex) + "." + toString(detLaneIndex);
232 loop = static_cast<MSInductLoop*>(nb.createInductLoop(id, placementLane, ilpos, detLength, "", myVehicleTypes, "", (int)PersonMode::NONE, myShowDetectors));
234 } else if (customID == NO_DETECTOR) {
235 continue;
236 } else {
238 if (loop == nullptr) {
239 throw ProcessError(TLF("Unknown inductionLoop '%' given as custom detector for actuated tlLogic '%', program '%.", customID, getID(), getProgramID()));
240 }
241 ilpos = loop->getPosition();
242 inductLoopPosition = length - ilpos;
243 }
244 const double maxGap = getDouble("max-gap:" + lane->getID(), myMaxGap);
245 const double jamThreshold = getDouble("jam-threshold:" + lane->getID(), myJamThreshold);
246 laneInductLoopMap[lane] = loop;
247 inductLoopInfoMap[loop] = (int)myInductLoops.size();
248 myInductLoops.push_back(InductLoopInfo(loop, lane, (int)myPhases.size(), maxGap, jamThreshold));
249
250 if (warn && floor(floor(inductLoopPosition / defaultLength) * myPassingTime) > STEPS2TIME(minDur)) {
251 // warn if the minGap is insufficient to clear vehicles between stop line and detector
252 WRITE_WARNINGF(TL("At actuated tlLogic '%', minDur % is too short for a detector gap of %m."), getID(), time2string(minDur), toString(inductLoopPosition));
253 warn = false;
254 }
255 }
256 }
257 // assign loops to phase index (myInductLoopsForPhase)
258 // check1: loops may not be used for a phase if there are other connections from the same lane that may not drive in that phase
259 // greenMinor is ambiguous as vehicles may not be able to drive
260 // Under the following condition we allow actuation from minor link:
261 // check1a : the minor link is minor in all phases
262 // check1b : there is another major link from the same lane in the current phase
263 // check1e : the conflict is only with bikes/pedestrians (i.e. for a right turn, also left turn with no oncoming traffic)
264 // check1f : the conflict is only with a link from the same edge
265 // (Under these conditions we assume that the minor link is unimportant and traffic is mostly for the major link)
266 //
267 // check1c: when the edge has only one lane, we treat greenMinor as green as there would be no actuation otherwise
268 // check1d: for turnarounds 1b is sufficient and we do not require 1a
269 //
270 // check2: if there are two loops on subsequent lanes (joined tls) and the second one has a red link, the first loop may not be used
271 //
272 // if a jamThreshold is specificed for the loop, all checks are ignored
273
274 // also assign loops to link index for validation:
275 // check if all links from actuated phases (minDur != maxDur) have an inductionloop in at least one phase
276 const SVCPermissions motorized = ~(SVC_PEDESTRIAN | SVC_BICYCLE);
277 std::map<int, std::set<MSInductLoop*> > linkToLoops;
278 std::set<int> actuatedLinks;
279
280 std::vector<bool> neverMajor(numLinks, true);
281 for (const MSPhaseDefinition* phase : myPhases) {
282 const std::string& state = phase->getState();
283 for (int i = 0; i < numLinks; i++) {
284 if (state[i] == LINKSTATE_TL_GREEN_MAJOR) {
285 neverMajor[i] = false;
286 }
287 }
288 }
289 std::vector<bool> oneLane(numLinks, false);
290 std::vector<bool> turnaround(numLinks, true);
291 for (int i = 0; i < numLinks; i++) {
292 for (MSLane* lane : getLanesAt(i)) {
293 // only count motorized vehicle lanes
294 int numMotorized = 0;
295 for (MSLane* l : lane->getEdge().getLanes()) {
296 if ((l->getPermissions() & motorized) != 0) {
297 numMotorized++;
298 }
299 }
300 if (numMotorized == 1) {
301 oneLane[i] = true;
302 break;
303 }
304 }
305 for (MSLink* link : getLinksAt(i)) {
306 if (!link->isTurnaround()) {
307 turnaround[i] = false;
308 break;
309 }
310 }
311 }
312
313 for (const MSPhaseDefinition* phase : myPhases) {
314 const int phaseIndex = (int)myInductLoopsForPhase.size();
315 std::set<MSInductLoop*> loops;
316 if (phase->isActuated() || multiNextTargets.count(phaseIndex) != 0) {
317 const std::string& state = phase->getState();
318 // collect indices of all green links for the phase
319 std::set<int> greenLinks;
320 // green links that could jam
321 std::set<int> greenLinksPermissive;
322 // collect green links for each induction loops (in this phase)
323 std::map<MSInductLoop*, std::set<int> > loopLinks;
324
325 for (int i = 0; i < numLinks; i++) {
326 if (state[i] == LINKSTATE_TL_GREEN_MAJOR) {
327 greenLinks.insert(i);
328 if (phase->isActuated()) {
329 actuatedLinks.insert(i);
330 }
331
332 for (MSLink* link : getLinksAt(i)) {
333 if (link->getLane()->isCrossing()) {
334 while (myCrossingsForPhase.size() < myPhases.size()) {
335 myCrossingsForPhase.push_back(std::vector<const MSLink*>());
336 }
337 myCrossingsForPhase[phaseIndex].push_back(link);
338 }
339 }
340
341 } else if (state[i] == LINKSTATE_TL_GREEN_MINOR) {
342 if (((neverMajor[i] || turnaround[i]) // check1a, 1d
343 && hasMajor(state, getLanesAt(i))) // check1b
344 || oneLane[i] // check1c
345 || weakConflict(i, state)) { // check1e, check1f
346 greenLinks.insert(i);
347 if (!turnaround[i]) {
348 if (phase->isActuated()) {
349 actuatedLinks.insert(i);
350 }
351 }
352 } else {
353 greenLinksPermissive.insert(i);
354 }
355 }
356#ifdef DEBUG_DETECTORS
357 if (DEBUG_COND) {
358 std::cout << " phase=" << phaseIndex << " i=" << i << " state=" << state[i] << " green=" << greenLinks.count(i) << " oneLane=" << oneLane[i]
359 << " turn=" << turnaround[i] << " loopLanes=";
360 for (MSLane* lane : getLanesAt(i)) {
361 if (laneInductLoopMap.count(lane) != 0) {
362 std::cout << lane->getID() << " ";
363 }
364 }
365 std::cout << "\n";
366 }
367#endif
368 for (MSLane* lane : getLanesAt(i)) {
369 if (laneInductLoopMap.count(lane) != 0) {
370 loopLinks[laneInductLoopMap[lane]].insert(i);
371 }
372 }
373 }
374 for (auto& item : loopLinks) {
375 MSInductLoop* loop = item.first;
376 const InductLoopInfo& info = myInductLoops[inductLoopInfoMap[loop]];
377 const MSLane* loopLane = info.lane;
378 bool usable = true;
379 bool foundUsable = false;
380 // check1
381 for (int j : item.second) {
382 if (greenLinks.count(j) == 0 && (info.jamThreshold <= 0 || greenLinksPermissive.count(j) == 0)) {
383 usable = false;
384#ifdef DEBUG_DETECTORS
385 if (DEBUG_COND) {
386 std::cout << " phase=" << phaseIndex << " check1: loopLane=" << loopLane->getID() << " notGreen=" << j << " oneLane[j]=" << oneLane[j] << "\n";
387 }
388#endif
389 } else {
390 foundUsable = true;
391 }
392 }
393 if (!usable && foundUsable && info.jamThreshold > 0) {
394 // permit green even when the same lane has green and red links (if we have jamDetection)
395 usable = true;
396 }
397 // check2 (skip if we have jam detection)
398 if (usable && info.jamThreshold <= 0) {
399 for (MSLink* link : loopLane->getLinkCont()) {
400 if (link->isTurnaround()) {
401 continue;
402 }
403 const MSLane* next = link->getLane();
404 if (laneInductLoopMap.count(next) != 0) {
405 MSInductLoop* nextLoop = laneInductLoopMap[next];
406 for (int j : loopLinks[nextLoop]) {
407 if (greenLinks.count(j) == 0) {
408 usable = false;
409#ifdef DEBUG_DETECTORS
410 if (DEBUG_COND) std::cout << " phase=" << phaseIndex << " check2: loopLane=" << loopLane->getID()
411 << " nextLane=" << next->getID() << " nextLink=" << j << " nextState=" << state[j] << "\n";
412#endif
413 break;
414 }
415 }
416 }
417 }
418 }
419
420 if (usable) {
421 loops.insert(item.first);
422#ifdef DEBUG_DETECTORS
423 if (DEBUG_COND) {
424 std::cout << " phase=" << phaseIndex << " usableLoops=" << item.first->getID() << " links=" << joinToString(item.second, " ") << "\n";
425 }
426#endif
427 for (int j : item.second) {
428 linkToLoops[j].insert(item.first);
429 }
430 }
431 }
432 if (loops.size() == 0 && phase->isActuated()) {
433 WRITE_WARNINGF(TL("At actuated tlLogic '%', actuated phase % has no controlling detector."), getID(), toString(phaseIndex));
434 }
435 }
436#ifdef DEBUG_DETECTORS
437 if (DEBUG_COND) {
438 std::cout << " phase=" << phaseIndex << " loops=" << joinNamedToString(loops, " ") << "\n";
439 }
440 if (DEBUG_COND) {
441 std::cout << " linkToLoops:\n";
442 for (auto item : linkToLoops) {
443 std::cout << " link=" << item.first << " loops=" << joinNamedToString(item.second, " ") << "\n";
444 }
445 }
446#endif
447 std::vector<InductLoopInfo*> loopInfos;
448 myInductLoopsForPhase.push_back(loopInfos);
449 for (MSInductLoop* loop : loops) {
450 for (InductLoopInfo& loopInfo : myInductLoops) {
451 if (loopInfo.loop == loop) {
452 myInductLoopsForPhase.back().push_back(&loopInfo);
453 loopInfo.servedPhase[phaseIndex] = true;
454 }
455 }
456 }
457 }
458#ifdef DEBUG_DETECTORS
459 if (DEBUG_COND) {
460 std::cout << "final linkToLoops:\n";
461 for (auto item : linkToLoops) {
462 std::cout << " link=" << item.first << " loops=" << joinNamedToString(item.second, " ") << "\n";
463 }
464 }
465#endif
466 std::vector<int> warnLinks;
467 for (int i : actuatedLinks) {
468 if (linkToLoops[i].size() == 0 && myLinks[i].size() > 0
469 && (myLinks[i].front()->getLaneBefore()->getPermissions() & motorized) != 0) {
470 if (getParameter(myLinks[i].front()->getLaneBefore()->getID()) != NO_DETECTOR) {
471 warnLinks.push_back(i);
472 }
473 }
474 }
475 if (warnLinks.size() > 0) {
476 WRITE_WARNINGF(TL("At actuated tlLogic '%', linkIndex % has no controlling detector."), getID(), joinToString(warnLinks, ","));
477 }
478 // parse maximum green times for each link (optional)
479 for (const auto& kv : getParametersMap()) {
480 if (StringUtils::startsWith(kv.first, "linkMaxDur:")) {
481 int link = StringUtils::toInt(kv.first.substr(11));
482 if (link < 0 || link >= myNumLinks) {
483 WRITE_ERRORF(TL("Invalid link '%' given as linkMaxDur parameter for actuated tlLogic '%', program '%."), kv.first.substr(11), getID(), getProgramID());
484 continue;
485 }
486 if (myLinkMaxGreenTimes.empty()) {
487 myLinkMaxGreenTimes = std::vector<SUMOTime>(myNumLinks, std::numeric_limits<SUMOTime>::max());
488 }
489 myLinkMaxGreenTimes[link] = string2time(kv.second);
490 } else if (StringUtils::startsWith(kv.first, "linkMinDur:")) {
491 int link = StringUtils::toInt(kv.first.substr(11));
492 if (link < 0 || link >= myNumLinks) {
493 WRITE_ERRORF(TL("Invalid link '%' given as linkMinDur parameter for actuated tlLogic '%', program '%."), kv.first.substr(11), getID(), getProgramID());
494 continue;
495 }
496 if (myLinkMinGreenTimes.empty()) {
497 myLinkMinGreenTimes = std::vector<SUMOTime>(myNumLinks, 0);
498 }
499 myLinkMinGreenTimes[link] = string2time(kv.second);
500 }
501 }
502 bool haveSwitchingRules = myConditions.size() > 0 || myAssignments.size() > 0 || myFunctions.size() > 0;
503 for (auto sr : mySwitchingRules) {
504 if (sr.enabled) {
505 haveSwitchingRules = true;
506 break;
507 }
508 }
509 if (myLinkMaxGreenTimes.size() > 0 || myLinkMinGreenTimes.size() > 0 || haveSwitchingRules) {
510 myLinkGreenTimes = std::vector<SUMOTime>(myNumLinks, 0);
511 myLinkRedTimes = std::vector<SUMOTime>(myNumLinks, 0);
512 }
513 //std::cout << SIMTIME << " linkMaxGreenTimes=" << toString(myLinkMaxGreenTimes) << "\n";
514}
515
516
517bool
518MSActuatedTrafficLightLogic::weakConflict(int tlIndex, const std::string& state) const {
519 for (MSLink* link : getLinksAt(tlIndex)) {
520 int linkIndex = link->getIndex();
521 const MSJunction* junction = link->getJunction();
522 for (int i = 0; i < (int)myLinks.size(); i++) {
523 if (i == tlIndex) {
524 continue;
525 }
526 if (state[i] == LINKSTATE_TL_GREEN_MAJOR || state[i] == LINKSTATE_TL_GREEN_MINOR) {
527 for (MSLink* foe : getLinksAt(i)) {
528 // junction logic is based on junction link index rather than tl index
529 int foeIndex = foe->getIndex();
530 const MSJunction* junction2 = foe->getJunction();
531 if (junction == junction2) {
532 const MSJunctionLogic* logic = junction->getLogic();
533 //std::cout << " greenLink=" << i << " isFoe=" << logic->getFoesFor(linkIndex).test(foeIndex) << "\n";
534 if (logic->getFoesFor(linkIndex).test(foeIndex)
535 && (foe->getPermissions() & ~SVC_VULNERABLE) != 0 // check1e
536 && &foe->getLaneBefore()->getEdge() != &link->getLaneBefore()->getEdge()) { // check1f
537 //std::cout << " strongConflict " << tlIndex << " in phase " << state << " with link " << foe->getTLIndex() << "\n";
538 return false;
539 }
540 }
541 }
542
543 }
544 }
545 }
546 //std::cout << " weakConflict " << tlIndex << " in phase " << state << "\n";
547 return true;
548}
549
550
553 step = step < 0 ? myStep : step;
554 const MSPhaseDefinition* p = myPhases[step];
556 ? p->minDuration
557 : TIME2STEPS(evalExpression(myConditions.find("minDur:" + toString(step))->second));
558}
559
562 step = step < 0 ? myStep : step;
563 const MSPhaseDefinition* p = myPhases[step];
565 ? p->maxDuration
566 : TIME2STEPS(evalExpression(myConditions.find("maxDur:" + toString(step))->second));
567}
568
571 step = step < 0 ? myStep : step;
572 const MSPhaseDefinition* p = myPhases[step];
574 ? p->earliestEnd
575 : TIME2STEPS(evalExpression(myConditions.find("earliestEnd:" + toString(step))->second));
576}
577
580 step = step < 0 ? myStep : step;
581 const MSPhaseDefinition* p = myPhases[step];
583 ? p->latestEnd
584 : TIME2STEPS(evalExpression(myConditions.find("latestEnd:" + toString(step))->second));
585}
586
587
588void
591 for (int i = 0; i < (int)myPhases.size(); i++) {
592 MSPhaseDefinition* phase = myPhases[i];
593 const std::string errorSuffix = "' for overriding attribute in phase " + toString(i) + " of tlLogic '" + getID() + "' in program '" + getProgramID() + "'.";
594 if (phase->minDuration == ovrd) {
595 const std::string cond = "minDur:" + toString(i);
596 if (myConditions.count(cond) == 0) {
597 throw ProcessError("Missing condition '" + cond + errorSuffix);
598 }
599 }
600 if (phase->maxDuration == ovrd) {
601 const std::string cond = "maxDur:" + toString(i);
602 if (myConditions.count(cond) == 0) {
603 throw ProcessError("Missing condition '" + cond + errorSuffix);
604 }
605 }
606 if (phase->earliestEnd == ovrd) {
607 const std::string cond = "earliestEnd:" + toString(i);
608 if (myConditions.count(cond) == 0) {
609 throw ProcessError("Missing condition '" + cond + errorSuffix);
610 }
611 }
612 if (phase->latestEnd == ovrd) {
613 const std::string cond = "latestEnd:" + toString(i);
614 if (myConditions.count(cond) == 0) {
615 throw ProcessError("Missing condition '" + cond + errorSuffix);
616 }
617 }
618 }
619}
620
621
622void
624 for (int i = 0; i < (int)myPhases.size(); i++) {
626 MSPhaseDefinition* phase = myPhases[i];
627 std::vector<int> nextPhases = phase->nextPhases;
628 if (nextPhases.size() == 0) {
629 nextPhases.push_back((i + 1) % (int)myPhases.size());
630 } else if (nextPhases.size() > 1) {
631 myHasMultiTarget = true;
632 }
633 for (int next : nextPhases) {
634 if (next >= 0 && next < (int)myPhases.size()) {
635 const MSPhaseDefinition* nextPhase = myPhases[next];
636 if (nextPhase->earlyTarget != "" || nextPhase->finalTarget != "") {
637 sr.enabled = true;
638 }
639 }
640 }
641 // simplifies later code
642 phase->nextPhases = nextPhases;
643 mySwitchingRules.push_back(sr);
644 }
645}
646
647
648void
650 // next -> target -> transitionTime starting from step
651 std::map<int, std::map<int, SUMOTime> > reached;
652 const std::vector<int>& next = myPhases[step]->nextPhases;
653 for (int n : next) {
654 findTargets(step, n, 0, reached[n]);
655 }
656 for (int target = 0; target < (int)myPhases.size(); target++) {
657 int bestNext = next[0];
658 SUMOTime bestTime = SUMOTime_MAX;
659 for (auto item : reached) {
660 auto it = item.second.find(target);
661 if (it != item.second.end()) {
662 SUMOTime transitionTime = it->second;
663 if (transitionTime < bestTime) {
664 bestTime = transitionTime;
665 bestNext = item.first;
666 }
667 }
668 }
669 if (bestTime != SUMOTime_MAX) {
670 myTargets[step][bestNext].push_back(target);
671 //std::cout << " myTargets step=" << step << " bestNext=" << bestNext << " target=" << target << "\n";
672 }
673 }
674}
675
676
677void
678MSActuatedTrafficLightLogic::findTargets(int origStep, int n, SUMOTime priorTransition, std::map<int, SUMOTime>& found) {
679 std::pair<int, SUMOTime> tDur = getTarget(n);
680 int target = tDur.first;
681 SUMOTime transitionTime = tDur.second + priorTransition;
682 //std::cout << " findTargets origStep=" << origStep << " n=" << n << " ptt=" << priorTransition << " target=" << target << " tt=" << transitionTime << "\n";
683 if (target == origStep) {
684 // full circle
685 //std::cout << " foundCircle\n";
686 return;
687 }
688 auto it = found.find(target);
689 if (it != found.end()) {
690 if (it->second <= transitionTime) {
691 //std::cout << " oldShorterTime=" << it->second << "\n";
692 // found the same target again
693 return;
694 } else {
695 //std::cout << " newShorterTime=" << it->second << "\n";
696 }
697 } else {
698 //std::cout << " newTarget\n";
699 }
700 found[target] = transitionTime;
701 //std::cout << " targetNext=" << toString(myPhases[target]->nextPhases) << "\n";
702 for (int n2 : myPhases[target]->nextPhases) {
703 findTargets(origStep, n2, transitionTime, found);
704 }
705}
706
707
708std::set<int>
710 std::set<int> result;
711 if (myHasMultiTarget) {
712 // find all phase that are the target green phase of a 'next' attribute
713 for (const MSPhaseDefinition* p : myPhases) {
714 for (int next : p->nextPhases) {
715 result.insert(getTarget(next).first);
716 }
717 }
718 }
719 return result;
720}
721
722
724MSActuatedTrafficLightLogic::getMinimumMinDuration(MSLane* lane, const std::set<int>& multiNextTargets) const {
725 SUMOTime result = std::numeric_limits<SUMOTime>::max();
726 for (int pI = 0; pI < (int)myPhases.size(); pI++) {
727 const MSPhaseDefinition* phase = myPhases[pI];
728 const std::string& state = phase->getState();
729 for (int i = 0; i < (int)state.size(); i++) {
730 if (state[i] == LINKSTATE_TL_GREEN_MAJOR || state[i] == LINKSTATE_TL_GREEN_MINOR) {
731 for (MSLane* cand : getLanesAt(i)) {
732 if (lane == cand) {
733 if (phase->isActuated()) {
734 result = MIN2(result, getMinDur(pI));
735 } else if (multiNextTargets.count(pI) != 0) {
736 result = MIN2(result, DEFAULT_STATIC_MINDUR);
737 }
738 }
739 }
740 }
741 }
742 }
743 return result;
744}
745
746bool
747MSActuatedTrafficLightLogic::hasMajor(const std::string& state, const LaneVector& lanes) const {
748 for (int i = 0; i < (int)state.size(); i++) {
749 if (state[i] == LINKSTATE_TL_GREEN_MAJOR) {
750 for (MSLane* cand : getLanesAt(i)) {
751 for (MSLane* lane : lanes) {
752 if (lane == cand) {
753 return true;
754 }
755 }
756 }
757 }
758 }
759 return false;
760}
761
762
763// ------------ Switching and setting current rows
764void
771
772
773void
776 for (InductLoopInfo& loopInfo : myInductLoops) {
777 loopInfo.loop->setVisible(false);
778 }
779}
780
781void
783 SUMOTime simStep, int step, SUMOTime stepDuration) {
784 // do not change timing if the phase changes
785 if (step >= 0 && step != myStep) {
786 myStep = step;
788 setTrafficLightSignals(simStep);
789 tlcontrol.get(getID()).executeOnSwitchActions();
790 } else if (step < 0) {
791 // TraCI requested new timing
793 mySwitchCommand = new SwitchCommand(tlcontrol, this, stepDuration + simStep);
795 mySwitchCommand, stepDuration + simStep);
796 myTraCISwitch = true;
797 }
798}
799
800
801void
803 const SUMOTime lastSwitch = t - spentDuration;
804 myStep = step;
805 myPhases[myStep]->myLastSwitch = lastSwitch;
806 const SUMOTime nextSwitch = t + getPhase(step).minDuration - spentDuration;
808 mySwitchCommand = new SwitchCommand(tlcontrol, this, nextSwitch);
810 setTrafficLightSignals(lastSwitch);
811 tlcontrol.get(getID()).executeOnSwitchActions();
812}
813
814
817 // checks if the actual phase should be continued
818 // @note any vehicles which arrived during the previous phases which are now waiting between the detector and the stop line are not
819 // considere here. RiLSA recommends to set minDuration in a way that lets all vehicles pass the detector
822
823 if (myLinkGreenTimes.size() > 0) {
824 // constraints exist, record green time durations for each link
825 const std::string& state = getCurrentPhaseDef().getState();
826 SUMOTime lastDuration = SIMSTEP - myLastTrySwitchTime;
827 for (int i = 0; i < myNumLinks; i++) {
828 if (state[i] == 'G' || state[i] == 'g') {
829 myLinkGreenTimes[i] += lastDuration;
830 } else {
831 myLinkGreenTimes[i] = 0;
832 }
833 if (state[i] == 'r' || state[i] == 'u') {
834 myLinkRedTimes[i] += lastDuration;
835 } else {
836 myLinkRedTimes[i] = 0;
837 }
838 }
839 }
841 // decide the next phase
842 const bool multiTarget = myPhases[myStep]->nextPhases.size() > 1 && myPhases[myStep]->nextPhases.front() >= 0;
843 const int origStep = myStep;
844 int nextStep = myStep;
845 SUMOTime actDuration = now - myPhases[myStep]->myLastSwitch;
846
847 if (mySwitchingRules[myStep].enabled) {
848 const bool mustSwitch = MIN2(getMaxDur() - actDuration, getLatest()) <= 0;
849 nextStep = decideNextPhaseCustom(mustSwitch);
850 } else {
851 // default algorithm
852 const double detectionGap = gapControl();
853#ifdef DEBUG_PHASE_SELECTION
854 if (DEBUG_COND) {
855 std::cout << SIMTIME << " p=" << myStep
856 << " trySwitch dGap=" << (detectionGap == std::numeric_limits<double>::max() ? "inf" : toString(detectionGap))
857 << " multi=" << multiTarget << "\n";
858 }
859#endif
860 if (detectionGap < std::numeric_limits<double>::max() && !multiTarget && !myTraCISwitch) {
861 return duration(detectionGap);
862 }
863 if (multiTarget) {
864 nextStep = decideNextPhase();
865 } else {
866 if (myPhases[myStep]->nextPhases.size() == 1 && myPhases[myStep]->nextPhases.front() >= 0) {
867 nextStep = myPhases[myStep]->nextPhases.front();
868 } else {
869 nextStep = (myStep + 1) % (int)myPhases.size();
870 }
871 }
872 }
873
874 myTraCISwitch = false;
875 if (myLinkMinGreenTimes.size() > 0) {
876 SUMOTime linkMinDur = getLinkMinDuration(getTarget(nextStep).first);
877 if (linkMinDur > 0) {
878 // for multiTarget, the current phase must be extended but if another
879 // targer is chosen, earlier switching than linkMinDur is possible
880 return multiTarget ? TIME2STEPS(1) : linkMinDur;
881 }
882 }
883 myStep = nextStep;
884 assert(myStep <= (int)myPhases.size());
885 assert(myStep >= 0);
886 //stores the time the phase started
887 const SUMOTime prevStart = myPhases[myStep]->myLastSwitch;
888 if (myStep != origStep) {
889 myPhases[origStep]->myLastEnd = now;
890 myPhases[myStep]->myLastSwitch = now;
891 actDuration = 0;
892 }
893 // activate coloring
894 if ((myShowDetectors || myHasMultiTarget) && getCurrentPhaseDef().isGreenPhase()) {
895 for (InductLoopInfo* loopInfo : myInductLoopsForPhase[myStep]) {
896 //std::cout << SIMTIME << " p=" << myStep << " loopinfo=" << loopInfo->loop->getID() << " set lastGreen=" << STEPS2TIME(now) << "\n";
897 if (loopInfo->isJammed()) {
898 loopInfo->loop->setSpecialColor(&RGBColor::ORANGE);
899 } else {
900 loopInfo->loop->setSpecialColor(&RGBColor::GREEN);
901 }
902 loopInfo->lastGreenTime = now;
903 }
904 }
905 // set the next event
906#ifdef DEBUG_PHASE_SELECTION
907 if (DEBUG_COND) {
908 std::cout << SIMTIME << " tl=" << getID() << " p=" << myStep
909 << " nextTryMinDur=" << STEPS2TIME(getMinDur() - actDuration)
910 << " nextTryEarliest=" << STEPS2TIME(getEarliest(prevStart)) << "\n";
911 }
912#endif
913 SUMOTime minRetry = myStep != origStep ? 0 : TIME2STEPS(1);
914 return MAX3(minRetry, getMinDur() - actDuration, getEarliest(prevStart));
915}
916
917
918// ------------ "actuated" algorithm methods
920MSActuatedTrafficLightLogic::duration(const double detectionGap) const {
921 assert(getCurrentPhaseDef().isGreenPhase());
922 assert((int)myPhases.size() > myStep);
923 const SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
924 // ensure that minimum duration is kept
925 SUMOTime newDuration = getMinDur() - actDuration;
926 // try to let the last detected vehicle pass the intersection (duration must be positive)
927 newDuration = MAX3(newDuration, TIME2STEPS(myDetectorGap - detectionGap), SUMOTime(1));
928 // cut the decimal places to ensure that phases always have integer duration
929 if (newDuration % 1000 != 0) {
930 const SUMOTime totalDur = newDuration + actDuration;
931 newDuration = (totalDur / 1000 + 1) * 1000 - actDuration;
932 }
933 // ensure that the maximum duration is not exceeded
934 newDuration = MIN3(newDuration, getMaxDur() - actDuration, getLatest());
935 return newDuration;
936}
937
938
939double
941 //intergreen times should not be lengthend
942 assert((int)myPhases.size() > myStep);
943 double result = std::numeric_limits<double>::max();
945 return result;
946 }
947 // switch off active colors
948 if (myShowDetectors) {
949 for (InductLoopInfo& loopInfo : myInductLoops) {
950 if (loopInfo.lastGreenTime < loopInfo.loop->getLastDetectionTime()) {
951 loopInfo.loop->setSpecialColor(&RGBColor::RED);
952 } else {
953 loopInfo.loop->setSpecialColor(nullptr);
954 }
955 }
956 }
958 return result; // end current phase
959 }
960
961 // Checks, if the maxDuration is kept. No phase should last longer than maxDuration.
962 SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
963 if (actDuration >= getCurrentPhaseDef().maxDuration || maxLinkDurationReached() || getLatest() == 0) {
964#ifdef DEBUG_PHASE_SELECTION
965 if (DEBUG_COND) {
966 std::cout << SIMTIME << " actDuration=" << STEPS2TIME(actDuration) << " maxDur=" << STEPS2TIME(getCurrentPhaseDef().maxDuration)
967 << " maxLinkDurationReached=" << maxLinkDurationReached() << " latest=" << STEPS2TIME(getLatest()) << "\n";
968 }
969#endif
970 return result; // end current phase
971 }
972
973 // now the gapcontrol starts
974 for (InductLoopInfo* loopInfo : myInductLoopsForPhase[myStep]) {
975 MSInductLoop* loop = loopInfo->loop;
976 if (loopInfo->isJammed()) {
977 loopInfo->loop->setSpecialColor(&RGBColor::ORANGE);
978 } else {
979 loopInfo->loop->setSpecialColor(&RGBColor::GREEN);
980 }
981 const double actualGap = loop->getTimeSinceLastDetection();
982 if (actualGap < loopInfo->maxGap && !loopInfo->isJammed()) {
983 result = MIN2(result, actualGap);
984 }
985 }
986 return result;
987}
988
989int
991 const auto& cands = myPhases[myStep]->nextPhases;
992 // decide by priority
993 // first target is the default when there is no traffic
994 // @note: to keep the current phase, even when there is no traffic, it must be added to 'next' explicitly
995 int result = cands.front();
996 int maxPrio = 0;
997 SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
998 const bool canExtend = actDuration < getCurrentPhaseDef().maxDuration && !maxLinkDurationReached() && getLatest() > 0;
999 if (canExtend) {
1000 // consider keeping the current phase until maxDur is reached
1001 // (only when there is still traffic in that phase)
1002 int currentPrio = getPhasePriority(myStep);
1003#ifdef DEBUG_PHASE_SELECTION
1004 std::cout << SIMTIME << " p=" << myStep << " loops=" << myInductLoopsForPhase[myStep].size() << " currentPrio=" << currentPrio << "\n";
1005#endif
1006 if (currentPrio > maxPrio) {
1007 result = myStep;
1008 maxPrio = currentPrio;
1009 }
1010 }
1011 for (int step : cands) {
1012 int prio = 0;
1013 for (int target : myTargets[myStep][step]) {
1014 prio += getPhasePriority(target);
1015#ifdef DEBUG_PHASE_SELECTION
1016 if (DEBUG_COND) {
1017 std::cout << SIMTIME << " p=" << myStep << " step=" << step << " target=" << target << " loops=" << myInductLoopsForPhase[target].size() << " prio=" << prio << "\n";
1018 }
1019#endif
1020 }
1021 if (prio > maxPrio && canExtendLinkGreen(getTarget(step).first)) {
1022 maxPrio = prio;
1023 result = step;
1024 }
1025 }
1026 return result;
1027}
1028
1029
1030std::pair<int, SUMOTime>
1032 int origStep = step;
1033 SUMOTime dur = 0;
1034 // if step is a transition, find the upcoming green phase
1035 while (!myPhases[step]->isGreenPhase()) {
1036 dur += myPhases[step]->duration;
1037 if (myPhases[step]->nextPhases.size() > 0 && myPhases[step]->nextPhases.front() >= 0) {
1038 if (myPhases[step]->nextPhases.size() > 1 && !mySwitchingRules[step].enabled) {
1039 WRITE_WARNINGF(TL("At actuated tlLogic '%', transition phase % should not have multiple next phases"), getID(), toString(step));
1040 }
1041 step = myPhases[step]->nextPhases.front();
1042 } else {
1043 step = (step + 1) % (int)myPhases.size();
1044 }
1045 if (step == origStep) {
1046 WRITE_WARNING("At actuated tlLogic '" + getID() + "', infinite transition loop from phase " + toString(origStep));
1047 return std::make_pair(0, 0);
1048 }
1049 }
1050 return std::make_pair(step, dur);
1051}
1052
1053int
1055 MSInductLoop* loop = loopInfo.loop;
1056 const double actualGap = loop->getTimeSinceLastDetection();
1057 if ((actualGap < loopInfo.maxGap && !loopInfo.isJammed())
1058 || loopInfo.lastGreenTime < loop->getLastDetectionTime()) {
1059 SUMOTime inactiveTime = MSNet::getInstance()->getCurrentTimeStep() - loopInfo.lastGreenTime;
1060 // @note. Inactive time could also be tracked regardless of current activity (to increase robustness in case of detection failure
1061 if (inactiveTime > myInactiveThreshold) {
1062#ifdef DEBUG_PHASE_SELECTION
1063 if (DEBUG_COND) {
1064 std::cout << " loop=" << loop->getID() << " gap=" << loop->getTimeSinceLastDetection() << " lastGreen=" << STEPS2TIME(loopInfo.lastGreenTime)
1065 << " lastDetection=" << STEPS2TIME(loop->getLastDetectionTime()) << " inactive=" << STEPS2TIME(inactiveTime) << "\n";
1066 }
1067#endif
1068 return (int)STEPS2TIME(inactiveTime);
1069 } else {
1070 // give bonus to detectors that are currently served (if that phase can stil be extended)
1071 if (loopInfo.servedPhase[myStep]) {
1072 SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
1073 const bool canExtend = actDuration < getCurrentPhaseDef().maxDuration && getLatest() > 0;
1074#ifdef DEBUG_PHASE_SELECTION
1075 if (DEBUG_COND) {
1076 std::cout << " loop=" << loop->getID()
1077 << " actDuration=" << STEPS2TIME(actDuration)
1078 << " maxDur=" << STEPS2TIME(getCurrentPhaseDef().maxDuration)
1079 << " getLatest=" << STEPS2TIME(getLatest())
1080 << " canExtend=" << canExtend
1081 << "\n";
1082 }
1083#endif
1084 if (canExtend) {
1086 } else {
1087 return 0;
1088 }
1089 }
1090 return 1;
1091 }
1092 }
1093 return 0;
1094}
1095
1096int
1098 int result = 0;
1099 for (const InductLoopInfo* loopInfo : myInductLoopsForPhase[step]) {
1100 result += getDetectorPriority(*loopInfo);
1101 }
1102 if (myCrossingsForPhase.size() > 0) {
1103 for (const MSLink* crossingEntry : myCrossingsForPhase[step]) {
1104 auto* aPersons = crossingEntry->getApproachingPersons();
1105 if (aPersons != nullptr && aPersons->size() > 0) {
1106 result += DEFAULT_CROSSING_PRIORITY;
1107 }
1108 }
1109 }
1110 return result;
1111}
1112
1113
1114void
1116 myShowDetectors = show;
1117 for (InductLoopInfo& loopInfo : myInductLoops) {
1118 loopInfo.loop->setVisible(myShowDetectors);
1119 }
1120}
1121
1122
1123bool
1125 if (myLinkMaxGreenTimes.empty()) {
1126 return false;
1127 }
1128 for (int i = 0; i < myNumLinks; i++) {
1130 //std::cout << SIMTIME << " maxLinkDurationReached i=" << i << "\n";
1131 return true;
1132 }
1133 }
1134 return false;
1135}
1136
1137bool
1139 if (myLinkMaxGreenTimes.empty()) {
1140 return true;
1141 }
1142 const std::string& targetState = myPhases[target]->getState();
1143 for (int i = 0; i < myNumLinks; i++) {
1144 if (myLinkGreenTimes[i] >= myLinkMaxGreenTimes[i] && (
1145 targetState[i] == 'G' || targetState[i] == 'g')) {
1146 //std::cout << SIMTIME << " cannotExtendLinkGreen target=" << target << " i=" << i << "\n";
1147 return false;
1148 }
1149 }
1150 return true;
1151}
1152
1155 SUMOTime result = 0;
1156 if (target != myStep && myLinkMinGreenTimes.size() > 0) {
1157 const std::string& state = myPhases[myStep]->getState();
1158 const std::string& targetState = myPhases[target]->getState();
1159 for (int i = 0; i < myNumLinks; i++) {
1161 && (state[i] == 'G' || state[i] == 'g')
1162 && !(targetState[i] == 'G' || targetState[i] == 'g')) {
1163 result = MAX2(result, myLinkMinGreenTimes[i] - myLinkGreenTimes[i]);
1164 //std::cout << SIMTIME << " getLinkMinDuration myStep=" << myStep << " target=" << target << " i=" << i
1165 // << " greenTime=" << STEPS2TIME(myLinkGreenTimes[i]) << " min=" << STEPS2TIME(myLinkMinGreenTimes[i]) << " result=" << STEPS2TIME(result) << "\n";
1166 }
1167 }
1168 }
1169 return result;
1170}
1171
1172int
1174 for (int next : getCurrentPhaseDef().nextPhases) {
1175 const MSPhaseDefinition* phase = myPhases[next];
1176 const std::string& condition = mustSwitch ? phase->finalTarget : phase->earlyTarget;
1177#ifdef DEBUG_PHASE_SELECTION_CUSTOM
1178 if (DEBUG_COND) {
1179 std::cout << SIMTIME << " mustSwitch=" << mustSwitch << " cur=" << myStep << " next=" << next << " condition=" << condition
1180 << " eval=" << (condition == "" ? NAN : evalExpression(condition)) << "\n";
1181 }
1182#endif
1183 if (condition != "") {
1184 // backward compatibility if a user redefined DEFAULT_CONDITION
1185 if (condition == DEFAULT_CONDITION && myConditions.count(DEFAULT_CONDITION) == 0) {
1186 if (gapControl() == std::numeric_limits<double>::max()) {
1187 return next;
1188 }
1189 } else if (evalExpression(condition)) {
1190 return next;
1191 }
1192 }
1193 }
1194 return mustSwitch ? getCurrentPhaseDef().nextPhases.back() : myStep;
1195}
1196
1197
1198double
1199MSActuatedTrafficLightLogic::evalExpression(const std::string& condition) const {
1200 const size_t bracketOpen = condition.find('(');
1201 if (bracketOpen != std::string::npos) {
1202 // find matching closing bracket
1203 size_t bracketClose = std::string::npos;
1204 int open = 1;
1205 for (size_t i = bracketOpen + 1; i < condition.size(); i++) {
1206 if (condition[i] == '(') {
1207 open++;
1208 } else if (condition[i] == ')') {
1209 open--;
1210 if (open == 0) {
1211 bracketClose = i;
1212 break;
1213 }
1214 }
1215 }
1216 if (bracketClose == std::string::npos) {
1217 throw ProcessError(TLF("Unmatched parentheses in condition %'", condition));
1218 }
1219 std::string cond2 = condition;
1220 const std::string inBracket = condition.substr(bracketOpen + 1, bracketClose - bracketOpen - 1);
1221 double bracketVal = evalExpression(inBracket);
1222 cond2.replace(bracketOpen, bracketClose - bracketOpen + 1, toString(bracketVal));
1223 try {
1224 return evalExpression(cond2);
1225 } catch (ProcessError& e) {
1226 throw ProcessError("Error when evaluating expression '" + condition + "':\n " + e.what());
1227 }
1228 }
1229 std::vector<std::string> tokens = StringTokenizer(condition).getVector();
1230 //std::cout << SIMTIME << " tokens(" << tokens.size() << ")=" << toString(tokens) << "\n";
1231 if (tokens.size() == 0) {
1232 throw ProcessError(TLF("Invalid empty condition '%'", condition));
1233 } else if (tokens.size() == 1) {
1234 try {
1235 return evalAtomicExpression(tokens[0]);
1236 } catch (ProcessError& e) {
1237 throw ProcessError("Error when evaluating expression '" + condition + "':\n " + e.what());
1238 }
1239 } else if (tokens.size() == 2) {
1240 if (tokens[0] == "not") {
1241 try {
1242 return evalAtomicExpression(tokens[1]) == 0. ? 1. : 0.;
1243 } catch (ProcessError& e) {
1244 throw ProcessError("Error when evaluating expression '" + condition + "':\n " + e.what());
1245 }
1246 } else {
1247 throw ProcessError(TLF("Unsupported condition '%'", condition));
1248 }
1249 } else if (tokens.size() == 3) {
1250 // infix expression
1251 const double a = evalAtomicExpression(tokens[0]);
1252 const double b = evalAtomicExpression(tokens[2]);
1253 const std::string& o = tokens[1];
1254 //std::cout << SIMTIME << " o=" << o << " a=" << a << " b=" << b << "\n";
1255 try {
1256 return evalTernaryExpression(a, o, b, condition);
1257 } catch (ProcessError& e) {
1258 throw ProcessError("Error when evaluating expression '" + condition + "':\n " + e.what());
1259 }
1260 } else {
1261 const int iEnd = (int)tokens.size() - 1;
1262 for (const std::string& o : OPERATOR_PRECEDENCE) {
1263 for (int i = 1; i < iEnd; i++) {
1264 if (tokens[i] == o) {
1265 try {
1266 const double val = evalTernaryExpression(
1267 evalAtomicExpression(tokens[i - 1]), o,
1268 evalAtomicExpression(tokens[i + 1]), condition);
1269 std::vector<std::string> newTokens(tokens.begin(), tokens.begin() + (i - 1));
1270 newTokens.push_back(toString(val));
1271 newTokens.insert(newTokens.end(), tokens.begin() + (i + 2), tokens.end());
1272 return evalExpression(toString(newTokens));
1273 } catch (ProcessError& e) {
1274 throw ProcessError("Error when evaluating expression '" + condition + "':\n " + e.what());
1275 }
1276 }
1277 }
1278 }
1279 throw ProcessError("Parsing expressions with " + toString(tokens.size()) + " elements ('" + condition + "') is not supported");
1280 }
1281 return true;
1282}
1283
1284double
1285MSActuatedTrafficLightLogic::evalTernaryExpression(double a, const std::string& o, double b, const std::string& condition) const {
1286 if (o == "=" || o == "==") {
1287 return (double)(a == b);
1288 } else if (o == "<") {
1289 return (double)(a < b);
1290 } else if (o == ">") {
1291 return (double)(a > b);
1292 } else if (o == "<=") {
1293 return (double)(a <= b);
1294 } else if (o == ">=") {
1295 return (double)(a >= b);
1296 } else if (o == "!=") {
1297 return (double)(a != b);
1298 } else if (o == "or" || o == "||") {
1299 return (double)(a || b);
1300 } else if (o == "and" || o == "&&") {
1301 return (double)(a && b);
1302 } else if (o == "+") {
1303 return a + b;
1304 } else if (o == "-") {
1305 return a - b;
1306 } else if (o == "*") {
1307 return a * b;
1308 } else if (o == "/") {
1309 if (b == 0) {
1310 WRITE_ERRORF(TL("Division by 0 in condition '%'"), condition);
1311 return 0;
1312 }
1313 return a / b;
1314 } else if (o == "%") {
1315 return fmod(a, b);
1316 } else if (o == "**" || o == "^") {
1317 return pow(a, b);
1318 } else {
1319 throw ProcessError("Unsupported operator '" + o + "' in condition '" + condition + "'");
1320 }
1321}
1322
1323double
1324MSActuatedTrafficLightLogic::evalCustomFunction(const std::string& fun, const std::string& arg) const {
1325 std::vector<std::string> args = StringTokenizer(arg, ",").getVector();
1326 const Function& f = myFunctions.find(fun)->second;
1327 if ((int)args.size() != f.nArgs) {
1328 throw ProcessError("Function '" + fun + "' requires " + toString(f.nArgs) + " arguments but " + toString(args.size()) + " were given");
1329 }
1330 std::vector<double> args2;
1331 for (auto a : args) {
1332 args2.push_back(evalExpression(a));
1333 }
1334 myStack.push_back(myStack.back());
1335 myStack.back()["$0"] = 0;
1336 for (int i = 0; i < (int)args2.size(); i++) {
1337 myStack.back()["$" + toString(i + 1)] = args2[i];
1338 }
1339 try {
1340 ConditionMap empty;
1342 } catch (ProcessError& e) {
1343 throw ProcessError("Error when evaluating function '" + fun + "' with args '" + joinToString(args2, ",") + "' (" + e.what() + ")");
1344 }
1345 double result = myStack.back()["$0"];
1346 myStack.pop_back();
1347 return result;
1348}
1349
1350
1351void
1352MSActuatedTrafficLightLogic::executeAssignments(const AssignmentMap& assignments, ConditionMap& conditions, const ConditionMap& forbidden) const {
1353 for (const auto& assignment : assignments) {
1354 if (evalExpression(std::get<1>(assignment))) {
1355 const std::string& id = std::get<0>(assignment);
1356 const double val = evalExpression(std::get<2>(assignment));
1357 ConditionMap::iterator it = conditions.find(id);
1358 if (it != conditions.end()) {
1359 it->second = toString(val);
1360 } else if (forbidden.find(id) != forbidden.end()) {
1361 throw ProcessError(TLF("Modifying global condition '%' is forbidden", id));
1362 } else {
1363 myStack.back()[id] = val;
1364 }
1365 }
1366 }
1367}
1368
1369
1370double
1372 if (expr.size() == 0) {
1373 throw ProcessError(TL("Invalid empty expression"));
1374 } else if (expr[0] == '!') {
1375 return evalAtomicExpression(expr.substr(1)) == 0. ? 1. : 0.;
1376 } else if (expr[0] == '-') {
1377 return -evalAtomicExpression(expr.substr(1));
1378 } else {
1379 // check for 'operator:'
1380 const size_t pos = expr.find(':');
1381 if (pos == std::string::npos) {
1382 auto it = myConditions.find(expr);
1383 if (it != myConditions.end()) {
1384 // symbol lookup
1385 return evalExpression(it->second);
1386 } else {
1387 // look at stack
1388 auto it2 = myStack.back().find(expr);
1389 if (it2 != myStack.back().end()) {
1390 return it2->second;
1391 }
1392 // must be a number
1393 return StringUtils::toDouble(expr);
1394 }
1395 } else {
1396 const std::string fun = expr.substr(0, pos);
1397 const std::string arg = expr.substr(pos + 1);
1398 if (fun == "z") {
1399 return retrieveDetExpression<MSInductLoop, SUMO_TAG_INDUCTION_LOOP>(arg, expr, true)->getTimeSinceLastDetection();
1400 } else if (fun == "a") {
1401 try {
1402 return retrieveDetExpression<MSInductLoop, SUMO_TAG_INDUCTION_LOOP>(arg, expr, true)->getTimeSinceLastDetection() == 0;
1403 } catch (ProcessError&) {
1404 return retrieveDetExpression<MSE2Collector, SUMO_TAG_LANE_AREA_DETECTOR>(arg, expr, true)->getCurrentVehicleNumber();
1405 }
1406 } else if (fun == "g" || fun == "r") {
1407 try {
1408 int linkIndex = StringUtils::toInt(arg);
1409 if (linkIndex >= 0 && linkIndex < myNumLinks) {
1410 const std::vector<SUMOTime>& times = fun == "g" ? myLinkGreenTimes : myLinkRedTimes;
1411 if (times.empty()) {
1412 return 0;
1413 }
1415 // times are only updated at the start of a phase where
1416 // switching is possible (i.e. not during minDur).
1417 // If somebody is looking at those values in the tracker
1418 // this would be confusing
1419 const LinkState ls = getCurrentPhaseDef().getSignalState(linkIndex);
1420 if ((fun == "g" && (ls == LINKSTATE_TL_GREEN_MAJOR || ls == LINKSTATE_TL_GREEN_MINOR))
1421 || (fun == "r" && (ls == LINKSTATE_TL_RED || ls == LINKSTATE_TL_REDYELLOW))) {
1422 const SUMOTime currentGreen = SIMSTEP - myLastTrySwitchTime;
1423 return STEPS2TIME(times[linkIndex] + currentGreen);
1424 } else {
1425 return 0;
1426 }
1427 } else {
1428 return STEPS2TIME(times[linkIndex]);
1429 }
1430 }
1431 } catch (NumberFormatException&) { }
1432 throw ProcessError("Invalid link index '" + arg + "' in expression '" + expr + "'");
1433 } else if (fun == "c") {
1434 return STEPS2TIME(getTimeInCycle());
1435 } else {
1436 if (myFunctions.find(fun) == myFunctions.end()) {
1437 throw ProcessError("Unsupported function '" + fun + "' in expression '" + expr + "'");
1438 }
1439 return evalCustomFunction(fun, arg);
1440 }
1441 }
1442 }
1443}
1444
1445
1446std::map<std::string, double>
1448 std::map<std::string, double> result;
1449 for (auto li : myInductLoops) {
1450 result[li.loop->getID()] = li.loop->getOccupancy() > 0 ? 1 : 0;
1451 }
1452 for (auto loop : myExtraLoops) {
1453 result[loop->getID()] = loop->getOccupancy() > 0 ? 1 : 0;
1454 }
1455 for (auto loop : myExtraE2) {
1456 result[loop->getID()] = loop->getCurrentVehicleNumber();
1457 }
1458 return result;
1459}
1460
1461double
1462MSActuatedTrafficLightLogic::getDetectorState(const std::string laneID) const {
1463 double result = 0.0;
1464 for (auto li : myInductLoops) {
1465 if (li.lane->getID() == laneID) {
1466 result = li.loop->getOccupancy() > 0 ? 1 : 0;
1467 break;
1468 }
1469 }
1470 return result;
1471}
1472
1473std::map<std::string, double>
1475 std::map<std::string, double> result;
1476 for (auto item : myConditions) {
1477 if (myListedConditions.count(item.first) != 0) {
1478 try {
1479 result[item.first] = evalExpression(item.second);
1480 } catch (ProcessError& e) {
1481 WRITE_ERRORF(TL("Error when retrieving conditions '%' for tlLogic '%' (%)"), item.first, getID(), e.what());
1482 }
1483 }
1484 }
1485 return result;
1486}
1487
1488const std::string
1489MSActuatedTrafficLightLogic::getParameter(const std::string& key, const std::string defaultValue) const {
1490 if (StringUtils::startsWith(key, "condition.")) {
1491 const std::string cond = key.substr(10);
1492 auto it = myConditions.find(cond);
1493 if (it != myConditions.end()) {
1494 return toString(evalExpression(it->second));
1495 } else {
1496 throw InvalidArgument("Unknown condition '" + cond + "' for actuated traffic light '" + getID() + "'");
1497 }
1498 } else {
1499 return MSSimpleTrafficLightLogic::getParameter(key, defaultValue);
1500 }
1501}
1502
1503void
1504MSActuatedTrafficLightLogic::setParameter(const std::string& key, const std::string& value) {
1505 // some pre-defined parameters can be updated at runtime
1506 if (key == "detector-gap" || key == "passing-time" || key == "file" || key == "freq" || key == "vTypes"
1507 || key == "build-all-detectors"
1508 || StringUtils::startsWith(key, "linkMaxDur")
1509 || StringUtils::startsWith(key, "linkMinDur")) {
1510 throw InvalidArgument(key + " cannot be changed dynamically for actuated traffic light '" + getID() + "'");
1511 } else if (key == "max-gap") {
1513 // overwrite custom values
1514 for (InductLoopInfo& loopInfo : myInductLoops) {
1515 loopInfo.maxGap = myMaxGap;
1516 }
1517 Parameterised::setParameter(key, value);
1518 } else if (StringUtils::startsWith(key, "max-gap:")) {
1519 const std::string laneID = key.substr(8);
1520 for (InductLoopInfo& loopInfo : myInductLoops) {
1521 if (loopInfo.lane->getID() == laneID) {
1522 loopInfo.maxGap = StringUtils::toDouble(value);
1523 Parameterised::setParameter(key, value);
1524 return;
1525 }
1526 }
1527 throw InvalidArgument("Invalid lane '" + laneID + "' in key '" + key + "' for actuated traffic light '" + getID() + "'");
1528 } else if (key == "jam-threshold") {
1530 // overwrite custom values
1531 for (InductLoopInfo& loopInfo : myInductLoops) {
1532 loopInfo.jamThreshold = myJamThreshold;
1533 }
1534 Parameterised::setParameter(key, value);
1535 } else if (StringUtils::startsWith(key, "jam-threshold:")) {
1536 const std::string laneID = key.substr(14);
1537 for (InductLoopInfo& loopInfo : myInductLoops) {
1538 if (loopInfo.lane->getID() == laneID) {
1539 loopInfo.jamThreshold = StringUtils::toDouble(value);
1540 Parameterised::setParameter(key, value);
1541 return;
1542 }
1543 }
1544 throw InvalidArgument("Invalid lane '" + laneID + "' in key '" + key + "' for actuated traffic light '" + getID() + "'");
1545 } else if (key == "show-detectors") {
1547 Parameterised::setParameter(key, value);
1548 for (InductLoopInfo& loopInfo : myInductLoops) {
1549 loopInfo.loop->setVisible(myShowDetectors);
1550 }
1551 } else if (key == "inactive-threshold") {
1553 Parameterised::setParameter(key, value);
1554 } else {
1556 }
1557}
1558
1559
1560/****************************************************************************/
long long int SUMOTime
Definition GUI.h:36
#define DEFAULT_DETECTOR_GAP
#define DEFAULT_MAX_GAP
#define DEFAULT_STATIC_MINDUR
#define DEFAULT_PASSING_TIME
#define DEFAULT_BIKE_LENGTH_WITH_GAP
#define DEFAULT_LENGTH_WITH_GAP
#define NO_DETECTOR
#define DEFAULT_INACTIVE_THRESHOLD
#define DEFAULT_CROSSING_PRIORITY
#define DEFAULT_CONDITION
#define DEFAULT_CURRENT_PRIORITY
#define WRITE_WARNINGF(...)
Definition MsgHandler.h:288
#define WRITE_ERRORF(...)
Definition MsgHandler.h:297
#define WRITE_WARNING(msg)
Definition MsgHandler.h:287
#define TL(string)
Definition MsgHandler.h:305
#define TLF(string,...)
Definition MsgHandler.h:307
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition SUMOTime.cpp:46
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:91
#define STEPS2TIME(x)
Definition SUMOTime.h:55
#define SIMSTEP
Definition SUMOTime.h:61
#define SUMOTime_MAX
Definition SUMOTime.h:34
#define SIMTIME
Definition SUMOTime.h:62
#define TIME2STEPS(x)
Definition SUMOTime.h:57
bool noVehicles(SVCPermissions permissions)
Returns whether an edge with the given permissions forbids vehicles.
long long int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
const double DEFAULT_BICYCLE_SPEED
@ SVC_BICYCLE
vehicle is a bicycle
@ SVC_PEDESTRIAN
pedestrian
@ SUMO_TAG_INDUCTION_LOOP
alternative tag for e1 detector
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic,...
@ LINKSTATE_TL_REDYELLOW
The link has red light (must brake) but indicates upcoming green.
@ LINKSTATE_TL_GREEN_MAJOR
The link has green light, may pass.
@ LINKSTATE_TL_RED
The link has red light (must brake)
@ LINKSTATE_TL_GREEN_MINOR
The link has green light, has to brake.
T MIN3(T a, T b, T c)
Definition StdDefs.h:89
T MIN2(T a, T b)
Definition StdDefs.h:76
T MAX2(T a, T b)
Definition StdDefs.h:82
T MAX3(T a, T b, T c)
Definition StdDefs.h:96
std::string joinNamedToString(const std::set< T *, C > &ns, const T_BETWEEN &between)
Definition ToString.h:317
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition ToString.h:283
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:46
static std::string checkForRelativity(const std::string &filename, const std::string &basePath)
Returns the path from a configuration so that it is accessable from the current working directory.
double myDetectorGap
The detector distance in seconds.
void findTargets(int origStep, int n, SUMOTime priorTransition, std::map< int, SUMOTime > &found)
FunctionMap myFunctions
The loaded functions.
double myJamThreshold
The minimum continuous occupancy time to mark a detector as jammed.
bool myBuildAllDetectors
Whether all detectors shall be built.
double myMaxGap
The maximum gap to check in seconds.
const std::string getParameter(const std::string &key, const std::string defaultValue="") const override
try to get the value of the given parameter (including prefixed parameters)
std::map< int, std::map< int, std::vector< int > > > myTargets
std::vector< SwitchingRules > mySwitchingRules
std::vector< std::map< std::string, double > > myStack
The function call stack;.
double evalAtomicExpression(const std::string &expr) const
evaluate atomic expression
SUMOTime trySwitch() override
Switches to the next phase.
std::set< int > getMultiNextTargets() const
find green phases target by a next attribute
SUMOTime myLastTrySwitchTime
last time trySwitch was called
int getDetectorPriority(const InductLoopInfo &loopInfo) const
SUMOTime myFreq
The frequency for aggregating detector output.
std::vector< const MSInductLoop * > myExtraLoops
extra loops for output/tracking
bool myShowDetectors
Whether the detectors shall be shown in the GUI.
std::vector< SUMOTime > myLinkMaxGreenTimes
maximum consecutive time that the given link may remain green
MSActuatedTrafficLightLogic(MSTLLogicControl &tlcontrol, const std::string &id, const std::string &programID, const SUMOTime offset, const MSSimpleTrafficLightLogic::Phases &phases, int step, SUMOTime delay, const Parameterised::Map &parameter, const std::string &basePath, const ConditionMap &conditions=ConditionMap(), const AssignmentMap &assignments=AssignmentMap(), const FunctionMap &functions=FunctionMap())
Constructor.
void loadState(MSTLLogicControl &tlcontrol, SUMOTime t, int step, SUMOTime spentDuration) override
restores the tls state
SUMOTime getMaxDur(int step=-1) const override
std::vector< std::vector< const MSLink * > > myCrossingsForPhase
AssignmentMap myAssignments
The condition assignments.
std::string myVehicleTypes
Whether detector output separates by vType.
double gapControl()
Return the minimum detection gap of all detectors if the current phase should be extended and double:...
std::vector< std::tuple< std::string, std::string, std::string > > AssignmentMap
std::set< std::string > myListedConditions
the conditions which shall be listed in GUITLLogicPhasesTrackerWindow
double evalExpression(const std::string &condition) const
evaluate custom switching condition
std::vector< SUMOTime > myLinkMinGreenTimes
minimum consecutive time that the given link must remain green
void changeStepAndDuration(MSTLLogicControl &tlcontrol, SUMOTime simStep, int step, SUMOTime stepDuration) override
Changes the current phase and her duration.
bool weakConflict(int linkIndex, const std::string &state) const
whether a given link has only weak mode foes that are green in the given state
static const std::vector< std::string > OPERATOR_PRECEDENCE
bool myHasMultiTarget
Whether any of the phases has multiple targets.
double myPassingTime
The passing time used in seconds.
SUMOTime getLinkMinDuration(int target) const
the minimum duratin for keeping the current phase due to linkMinDur constraints
SUMOTime getMinDur(int step=-1) const override
bool canExtendLinkGreen(int target)
whether the target phase is acceptable in light of linkMaxDur constraints
InductLoopMap myInductLoopsForPhase
A map from phase to induction loops to be used for gap control.
SUMOTime getMinimumMinDuration(MSLane *lane, const std::set< int > &multiNextTargets) const
get the minimum min duration for all stretchable phases that affect the given lane
int decideNextPhaseCustom(bool mustSwitch)
select among candidate phases based on detector states and custom switching rules
double evalTernaryExpression(double a, const std::string &o, double b, const std::string &condition) const
evaluate atomic expression
void executeAssignments(const AssignmentMap &assignments, ConditionMap &conditions, const ConditionMap &forbidden=ConditionMap()) const
execute assignemnts of the logic or a custom function
bool myTraCISwitch
whether the next switch time was requested via TraCI
int getPhasePriority(int step) const
count the number of active detectors for the given step
SUMOTime duration(const double detectionGap) const
Returns the minimum duration of the current phase.
void activateProgram() override
called when switching programs
std::vector< InductLoopInfo > myInductLoops
bool maxLinkDurationReached()
whether the current phase cannot be continued due to linkMaxDur constraints
double evalCustomFunction(const std::string &fun, const std::string &arg) const
evaluate function expression
void initAttributeOverride()
initialize custom switching rules
std::map< std::string, double > getConditions() const override
return all named conditions defined for this traffic light
bool hasMajor(const std::string &state, const LaneVector &lanes) const
return whether there is a major link from the given lane in the given phase
std::vector< const MSE2Collector * > myExtraE2
SUMOTime getEarliestEnd(int step=-1) const override
std::map< std::string, Function > FunctionMap
std::map< std::string, double > getDetectorStates() const override
retrieve all detectors used by this program
double getDetectorState(const std::string laneID) const override
retrieve a specific detector used by this program
void setParameter(const std::string &key, const std::string &value) override
Sets a parameter and updates internal constants.
std::vector< SUMOTime > myLinkGreenTimes
consecutive time that the given link index has been green
SUMOTime getLatestEnd(int step=-1) const override
std::string myFile
The output file for generated detectors.
std::pair< int, SUMOTime > getTarget(int step) const
get the green phase following step and the transition time
ConditionMap myConditions
The custom switching conditions.
void init(NLDetectorBuilder &nb) override
Initialises the tls with information about incoming lanes.
int decideNextPhase()
select among candidate phases based on detector states
SUMOTime myInactiveThreshold
The time threshold to avoid starved phases.
const NamedObjectCont< MSDetectorFileOutput * > & getTypedDetectors(SumoXMLTag type) const
Returns the list of detectors of the given type.
void add(SumoXMLTag type, MSDetectorFileOutput *d, const std::string &device, SUMOTime interval, SUMOTime begin=-1)
Adds a detector/output combination into the containers.
A road/street connecting two junctions.
Definition MSEdge.h:77
double getSpeedLimit() const
Returns the speed limit of the edge @caution The speed limit of the first lane is retured; should pro...
Definition MSEdge.cpp:1157
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
static bool gUseMesoSim
Definition MSGlobals.h:106
An unextended detector measuring at a fixed position on a fixed lane.
double getPosition() const
Returns the position of the detector on the lane.
virtual void setSpecialColor(const RGBColor *)
allows for special color in the gui version
double getTimeSinceLastDetection() const
Returns the time since the last vehicle left the detector.
SUMOTime getLastDetectionTime() const
return last time a vehicle was on the detector
The base class for an intersection.
Definition MSJunction.h:58
virtual const MSJunctionLogic * getLogic() const
Definition MSJunction.h:141
virtual const MSLogicJunction::LinkBits & getFoesFor(int linkIndex) const
Returns the foes for the given link.
Representation of a lane in the micro simulation.
Definition MSLane.h:84
const std::vector< IncomingLaneInfo > & getIncomingLanes() const
Definition MSLane.h:950
double getLength() const
Returns the lane's length.
Definition MSLane.h:606
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition MSLane.cpp:3190
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:724
MSDetectorControl & getDetectorControl()
Returns the detector control.
Definition MSNet.h:446
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:186
MSEventControl * getBeginOfTimestepEvents()
Returns the event control for events executed at the begin of a time step.
Definition MSNet.h:476
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:325
The definition of a single phase of a tls logic.
SUMOTime maxDuration
The maximum duration of the phase.
LinkState getSignalState(int pos) const
Returns the state of the tls signal at the given position.
static const SUMOTime OVERRIDE_DURATION
SUMOTime latestEnd
The maximum time within the cycle for switching (for coordinated actuation)
SUMOTime minDuration
The minimum duration of the phase.
const std::string & getState() const
Returns the state within this phase.
bool isGreenPhase() const
Returns whether this phase is a pure "green" phase.
std::vector< int > nextPhases
The index of the phase that suceeds this one (or -1)
std::string finalTarget
The condition expression for switching into this phase when the active phase must end.
std::string earlyTarget
The condition expression for an early switch into this phase.
SUMOTime earliestEnd
The minimum time within the cycle for switching (for coordinated actuation)
A fixed traffic light logic.
SUMOTime getLatest() const
the maximum duration for keeping the current phase when considering 'latestEnd'
Phases myPhases
The list of phases this logic uses.
const MSPhaseDefinition & getPhase(int givenstep) const override
Returns the definition of the phase from the given position within the plan.
SUMOTime getEarliest(SUMOTime prevStart) const
the minimum duration for keeping the current phase when considering 'earliestEnd'
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const override
gets a parameter
virtual void setParameter(const std::string &key, const std::string &value) override
Sets a parameter and updates internal constants.
const MSPhaseDefinition & getCurrentPhaseDef() const override
Returns the definition of the current phase.
A class that stores and controls tls and switching of their programs.
TLSLogicVariants & get(const std::string &id) const
Returns the variants of a named tls.
Class realising the switch between the traffic light phases.
void deschedule(MSTrafficLightLogic *tlLogic)
Marks this swicth as invalid (if the phase duration has changed, f.e.)
const LaneVector & getLanesAt(int i) const
Returns the list of lanes that are controlled by the signals at the given position.
std::vector< MSLane * > LaneVector
Definition of the list of arrival lanes subjected to this tls.
SUMOTime getTimeInCycle() const
return time within the current cycle
const std::string & getProgramID() const
Returns this tl-logic's id.
LaneVectorVector myLanes
The list of LaneVectors; each vector contains the incoming lanes that belong to the same link index.
SwitchCommand * mySwitchCommand
The current switch command.
int myNumLinks
number of controlled links
virtual void activateProgram()
called when switching programs
bool setTrafficLightSignals(SUMOTime t) const
Applies the current signal states to controlled links.
std::vector< MSPhaseDefinition * > Phases
Definition of a list of phases, being the junction logic.
const LinkVector & getLinksAt(int i) const
Returns the list of links that are controlled by the signals at the given position.
LinkVectorVector myLinks
The list of LinkVectors; each vector contains the links that belong to the same link index.
virtual void init(NLDetectorBuilder &nb)
Initialises the tls with information about incoming lanes.
Builds detectors for microsim.
virtual MSDetectorFileOutput * createInductLoop(const std::string &id, MSLane *lane, double pos, double length, const std::string name, const std::string &vTypes, const std::string &nextEdges, int detectPersons, bool show)
Creates an instance of an e1 detector using the given values.
const std::string & getID() const
Returns the id.
Definition Named.h:74
T get(const std::string &id) const
Retrieves an item.
static OptionsCont & getOptions()
Retrieves the options.
bool hasParameter(const std::string &key) const
Returns whether the parameter is set.
std::map< std::string, std::string > Map
parameters map
double getDouble(const std::string &key, const double defaultValue) const
Returns the value for a given key converted to a double.
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.
static const RGBColor ORANGE
Definition RGBColor.h:194
static const RGBColor GREEN
Definition RGBColor.h:189
static const RGBColor RED
named colors
Definition RGBColor.h:188
std::vector< std::string > getVector()
return vector of strings
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
static bool toBool(const std::string &sData)
converts a string into the bool value described by it by calling the char-type converter
#define DEBUG_COND