Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
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-2026 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->getLogicalPredecessorLane() != nullptr
223 && placementLane->getIncomingLanes().front().viaLink->getCorrespondingEntryLink()->getTLLogic() == nullptr) {
224 placementLane = placementLane->getLogicalPredecessorLane();
225 ilpos += placementLane->getLength();
226 }
227 if (ilpos < 0) {
228 ilpos = 0;
229 }
230 // Build the induct loop and set it into the container
231 const double detLength = getDouble("detector-length:" + lane->getID(), detDefaultLength);
232 std::string id = myDetectorPrefix + "D" + toString(detEdgeIndex) + "." + toString(detLaneIndex);
233 loop = static_cast<MSInductLoop*>(nb.createInductLoop(id, placementLane, ilpos, detLength, "", myVehicleTypes, "", (int)PersonMode::NONE, myShowDetectors, true));
235 } else if (customID == NO_DETECTOR) {
236 continue;
237 } else {
239 if (loop == nullptr) {
240 throw ProcessError(TLF("Unknown inductionLoop '%' given as custom detector for actuated tlLogic '%', program '%.", customID, getID(), getProgramID()));
241 }
242 ilpos = loop->getPosition();
243 inductLoopPosition = length - ilpos;
244 }
245 const double maxGap = getDouble("max-gap:" + lane->getID(), myMaxGap);
246 const double jamThreshold = getDouble("jam-threshold:" + lane->getID(), myJamThreshold);
247 laneInductLoopMap[lane] = loop;
248 inductLoopInfoMap[loop] = (int)myInductLoops.size();
249 myInductLoops.push_back(InductLoopInfo(loop, lane, (int)myPhases.size(), maxGap, jamThreshold));
250
251 if (warn && floor(floor(inductLoopPosition / defaultLength) * myPassingTime) > STEPS2TIME(minDur)) {
252 // warn if the minGap is insufficient to clear vehicles between stop line and detector
253 WRITE_WARNINGF(TL("At actuated tlLogic '%', minDur % is too short for a detector gap of %m."), getID(), time2string(minDur), toString(inductLoopPosition));
254 warn = false;
255 }
256 }
257 }
258 // assign loops to phase index (myInductLoopsForPhase)
259 // 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
260 // greenMinor is ambiguous as vehicles may not be able to drive
261 // Under the following condition we allow actuation from minor link:
262 // check1a : the minor link is minor in all phases
263 // check1b : there is another major link from the same lane in the current phase
264 // check1e : the conflict is only with bikes/pedestrians (i.e. for a right turn, also left turn with no oncoming traffic)
265 // check1f : the conflict is only with a link from the same edge
266 // (Under these conditions we assume that the minor link is unimportant and traffic is mostly for the major link)
267 //
268 // check1c: when the edge has only one lane, we treat greenMinor as green as there would be no actuation otherwise
269 // check1d: for turnarounds 1b is sufficient and we do not require 1a
270 //
271 // 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
272 //
273 // if a jamThreshold is specificed for the loop, all checks are ignored
274
275 // also assign loops to link index for validation:
276 // check if all links from actuated phases (minDur != maxDur) have an inductionloop in at least one phase
277 const SVCPermissions motorized = ~(SVC_PEDESTRIAN | SVC_BICYCLE);
278 std::map<int, std::set<MSInductLoop*> > linkToLoops;
279 std::set<int> actuatedLinks;
280
281 std::vector<bool> neverMajor(numLinks, true);
282 for (const MSPhaseDefinition* phase : myPhases) {
283 const std::string& state = phase->getState();
284 for (int i = 0; i < numLinks; i++) {
285 if (state[i] == LINKSTATE_TL_GREEN_MAJOR) {
286 neverMajor[i] = false;
287 }
288 }
289 }
290 std::vector<bool> oneLane(numLinks, false);
291 std::vector<bool> turnaround(numLinks, true);
292 for (int i = 0; i < numLinks; i++) {
293 for (MSLane* lane : getLanesAt(i)) {
294 // only count motorized vehicle lanes
295 int numMotorized = 0;
296 for (MSLane* l : lane->getEdge().getLanes()) {
297 if ((l->getPermissions() & motorized) != 0) {
298 numMotorized++;
299 }
300 }
301 if (numMotorized == 1) {
302 oneLane[i] = true;
303 break;
304 }
305 }
306 for (MSLink* link : getLinksAt(i)) {
307 if (!link->isTurnaround()) {
308 turnaround[i] = false;
309 break;
310 }
311 }
312 }
313
314 for (const MSPhaseDefinition* phase : myPhases) {
315 const int phaseIndex = (int)myInductLoopsForPhase.size();
316 std::set<MSInductLoop*> loops;
317 if (phase->isActuated() || multiNextTargets.count(phaseIndex) != 0) {
318 const std::string& state = phase->getState();
319 // collect indices of all green links for the phase
320 std::set<int> greenLinks;
321 // green links that could jam
322 std::set<int> greenLinksPermissive;
323 // collect green links for each induction loops (in this phase)
324 std::map<MSInductLoop*, std::set<int> > loopLinks;
325
326 for (int i = 0; i < numLinks; i++) {
327 if (state[i] == LINKSTATE_TL_GREEN_MAJOR) {
328 greenLinks.insert(i);
329 if (phase->isActuated()) {
330 actuatedLinks.insert(i);
331 }
332
333 for (MSLink* link : getLinksAt(i)) {
334 if (link->getLane()->isCrossing()) {
335 while (myCrossingsForPhase.size() < myPhases.size()) {
336 myCrossingsForPhase.push_back(std::vector<const MSLink*>());
337 }
338 myCrossingsForPhase[phaseIndex].push_back(link);
339 }
340 }
341
342 } else if (state[i] == LINKSTATE_TL_GREEN_MINOR) {
343 if (((neverMajor[i] || turnaround[i]) // check1a, 1d
344 && hasMajor(state, getLanesAt(i))) // check1b
345 || oneLane[i] // check1c
346 || weakConflict(i, state)) { // check1e, check1f
347 greenLinks.insert(i);
348 if (!turnaround[i]) {
349 if (phase->isActuated()) {
350 actuatedLinks.insert(i);
351 }
352 }
353 } else {
354 greenLinksPermissive.insert(i);
355 }
356 }
357#ifdef DEBUG_DETECTORS
358 if (DEBUG_COND) {
359 std::cout << " phase=" << phaseIndex << " i=" << i << " state=" << state[i] << " green=" << greenLinks.count(i) << " oneLane=" << oneLane[i]
360 << " turn=" << turnaround[i] << " loopLanes=";
361 for (MSLane* lane : getLanesAt(i)) {
362 if (laneInductLoopMap.count(lane) != 0) {
363 std::cout << lane->getID() << " ";
364 }
365 }
366 std::cout << "\n";
367 }
368#endif
369 for (MSLane* lane : getLanesAt(i)) {
370 if (laneInductLoopMap.count(lane) != 0) {
371 loopLinks[laneInductLoopMap[lane]].insert(i);
372 }
373 }
374 }
375 for (auto& item : loopLinks) {
376 MSInductLoop* loop = item.first;
377 const InductLoopInfo& info = myInductLoops[inductLoopInfoMap[loop]];
378 const MSLane* loopLane = info.lane;
379 bool usable = true;
380 bool foundUsable = false;
381 // check1
382 for (int j : item.second) {
383 if (greenLinks.count(j) == 0 && (info.jamThreshold <= 0 || greenLinksPermissive.count(j) == 0)) {
384 usable = false;
385#ifdef DEBUG_DETECTORS
386 if (DEBUG_COND) {
387 std::cout << " phase=" << phaseIndex << " check1: loopLane=" << loopLane->getID() << " notGreen=" << j << " oneLane[j]=" << oneLane[j] << "\n";
388 }
389#endif
390 } else {
391 foundUsable = true;
392 }
393 }
394 if (!usable && foundUsable && info.jamThreshold > 0) {
395 // permit green even when the same lane has green and red links (if we have jamDetection)
396 usable = true;
397 }
398 // check2 (skip if we have jam detection)
399 if (usable && info.jamThreshold <= 0) {
400 for (MSLink* link : loopLane->getLinkCont()) {
401 if (link->isTurnaround()) {
402 continue;
403 }
404 const MSLane* next = link->getLane();
405 if (laneInductLoopMap.count(next) != 0) {
406 MSInductLoop* nextLoop = laneInductLoopMap[next];
407 for (int j : loopLinks[nextLoop]) {
408 if (greenLinks.count(j) == 0) {
409 usable = false;
410#ifdef DEBUG_DETECTORS
411 if (DEBUG_COND) std::cout << " phase=" << phaseIndex << " check2: loopLane=" << loopLane->getID()
412 << " nextLane=" << next->getID() << " nextLink=" << j << " nextState=" << state[j] << "\n";
413#endif
414 break;
415 }
416 }
417 }
418 }
419 }
420
421 if (usable) {
422 loops.insert(item.first);
423#ifdef DEBUG_DETECTORS
424 if (DEBUG_COND) {
425 std::cout << " phase=" << phaseIndex << " usableLoops=" << item.first->getID() << " links=" << joinToString(item.second, " ") << "\n";
426 }
427#endif
428 for (int j : item.second) {
429 linkToLoops[j].insert(item.first);
430 }
431 }
432 }
433 if (loops.size() == 0 && phase->isActuated()) {
434 WRITE_WARNINGF(TL("At actuated tlLogic '%', actuated phase % has no controlling detector."), getID(), toString(phaseIndex));
435 }
436 }
437#ifdef DEBUG_DETECTORS
438 if (DEBUG_COND) {
439 std::cout << " phase=" << phaseIndex << " loops=" << joinNamedToString(loops, " ") << "\n";
440 }
441 if (DEBUG_COND) {
442 std::cout << " linkToLoops:\n";
443 for (auto item : linkToLoops) {
444 std::cout << " link=" << item.first << " loops=" << joinNamedToString(item.second, " ") << "\n";
445 }
446 }
447#endif
448 std::vector<InductLoopInfo*> loopInfos;
449 myInductLoopsForPhase.push_back(loopInfos);
450 for (MSInductLoop* loop : loops) {
451 for (InductLoopInfo& loopInfo : myInductLoops) {
452 if (loopInfo.loop == loop) {
453 myInductLoopsForPhase.back().push_back(&loopInfo);
454 loopInfo.servedPhase[phaseIndex] = true;
455 }
456 }
457 }
458 }
459#ifdef DEBUG_DETECTORS
460 if (DEBUG_COND) {
461 std::cout << "final linkToLoops:\n";
462 for (auto item : linkToLoops) {
463 std::cout << " link=" << item.first << " loops=" << joinNamedToString(item.second, " ") << "\n";
464 }
465 }
466#endif
467 std::vector<int> warnLinks;
468 for (int i : actuatedLinks) {
469 if (linkToLoops[i].size() == 0 && myLinks[i].size() > 0
470 && (myLinks[i].front()->getLaneBefore()->getPermissions() & motorized) != 0) {
471 if (getParameter(myLinks[i].front()->getLaneBefore()->getID()) != NO_DETECTOR) {
472 warnLinks.push_back(i);
473 }
474 }
475 }
476 if (warnLinks.size() > 0) {
477 WRITE_WARNINGF(TL("At actuated tlLogic '%', linkIndex % has no controlling detector."), getID(), joinToString(warnLinks, ","));
478 }
479 // parse maximum green times for each link (optional)
480 for (const auto& kv : getParametersMap()) {
481 if (StringUtils::startsWith(kv.first, "linkMaxDur:")) {
482 int link = StringUtils::toInt(kv.first.substr(11));
483 if (link < 0 || link >= myNumLinks) {
484 WRITE_ERRORF(TL("Invalid link '%' given as linkMaxDur parameter for actuated tlLogic '%', program '%."), kv.first.substr(11), getID(), getProgramID());
485 continue;
486 }
487 if (myLinkMaxGreenTimes.empty()) {
488 myLinkMaxGreenTimes = std::vector<SUMOTime>(myNumLinks, std::numeric_limits<SUMOTime>::max());
489 }
490 myLinkMaxGreenTimes[link] = string2time(kv.second);
491 } else if (StringUtils::startsWith(kv.first, "linkMinDur:")) {
492 int link = StringUtils::toInt(kv.first.substr(11));
493 if (link < 0 || link >= myNumLinks) {
494 WRITE_ERRORF(TL("Invalid link '%' given as linkMinDur parameter for actuated tlLogic '%', program '%."), kv.first.substr(11), getID(), getProgramID());
495 continue;
496 }
497 if (myLinkMinGreenTimes.empty()) {
498 myLinkMinGreenTimes = std::vector<SUMOTime>(myNumLinks, 0);
499 }
500 myLinkMinGreenTimes[link] = string2time(kv.second);
501 }
502 }
503 bool haveSwitchingRules = myConditions.size() > 0 || myAssignments.size() > 0 || myFunctions.size() > 0;
504 for (auto sr : mySwitchingRules) {
505 if (sr.enabled) {
506 haveSwitchingRules = true;
507 break;
508 }
509 }
510 if (myLinkMaxGreenTimes.size() > 0 || myLinkMinGreenTimes.size() > 0 || haveSwitchingRules) {
511 myLinkGreenTimes = std::vector<SUMOTime>(myNumLinks, 0);
512 myLinkRedTimes = std::vector<SUMOTime>(myNumLinks, 0);
513 }
514 //std::cout << SIMTIME << " linkMaxGreenTimes=" << toString(myLinkMaxGreenTimes) << "\n";
515}
516
517
518bool
519MSActuatedTrafficLightLogic::weakConflict(int tlIndex, const std::string& state) const {
520 for (MSLink* link : getLinksAt(tlIndex)) {
521 int linkIndex = link->getIndex();
522 const MSJunction* junction = link->getJunction();
523 for (int i = 0; i < (int)myLinks.size(); i++) {
524 if (i == tlIndex) {
525 continue;
526 }
527 if (state[i] == LINKSTATE_TL_GREEN_MAJOR || state[i] == LINKSTATE_TL_GREEN_MINOR) {
528 for (MSLink* foe : getLinksAt(i)) {
529 // junction logic is based on junction link index rather than tl index
530 int foeIndex = foe->getIndex();
531 const MSJunction* junction2 = foe->getJunction();
532 if (junction == junction2) {
533 const MSJunctionLogic* logic = junction->getLogic();
534 //std::cout << " greenLink=" << i << " isFoe=" << logic->getFoesFor(linkIndex).test(foeIndex) << "\n";
535 if (logic->getFoesFor(linkIndex).test(foeIndex)
536 && (foe->getPermissions() & ~SVC_VULNERABLE) != 0 // check1e
537 && &foe->getLaneBefore()->getEdge() != &link->getLaneBefore()->getEdge()) { // check1f
538 //std::cout << " strongConflict " << tlIndex << " in phase " << state << " with link " << foe->getTLIndex() << "\n";
539 return false;
540 }
541 }
542 }
543
544 }
545 }
546 }
547 //std::cout << " weakConflict " << tlIndex << " in phase " << state << "\n";
548 return true;
549}
550
551
554 step = step < 0 ? myStep : step;
555 const MSPhaseDefinition* p = myPhases[step];
557 ? p->minDuration
558 : TIME2STEPS(evalExpression(myConditions.find("minDur:" + toString(step))->second));
559}
560
563 step = step < 0 ? myStep : step;
564 const MSPhaseDefinition* p = myPhases[step];
566 ? p->maxDuration
567 : TIME2STEPS(evalExpression(myConditions.find("maxDur:" + toString(step))->second));
568}
569
572 step = step < 0 ? myStep : step;
573 const MSPhaseDefinition* p = myPhases[step];
575 ? p->earliestEnd
576 : TIME2STEPS(evalExpression(myConditions.find("earliestEnd:" + toString(step))->second));
577}
578
581 step = step < 0 ? myStep : step;
582 const MSPhaseDefinition* p = myPhases[step];
584 ? p->latestEnd
585 : TIME2STEPS(evalExpression(myConditions.find("latestEnd:" + toString(step))->second));
586}
587
588
589void
592 for (int i = 0; i < (int)myPhases.size(); i++) {
593 MSPhaseDefinition* phase = myPhases[i];
594 const std::string errorSuffix = "' for overriding attribute in phase " + toString(i) + " of tlLogic '" + getID() + "' in program '" + getProgramID() + "'.";
595 if (phase->minDuration == ovrd) {
596 const std::string cond = "minDur:" + toString(i);
597 if (myConditions.count(cond) == 0) {
598 throw ProcessError("Missing condition '" + cond + errorSuffix);
599 }
600 }
601 if (phase->maxDuration == ovrd) {
602 const std::string cond = "maxDur:" + toString(i);
603 if (myConditions.count(cond) == 0) {
604 throw ProcessError("Missing condition '" + cond + errorSuffix);
605 }
606 }
607 if (phase->earliestEnd == ovrd) {
608 const std::string cond = "earliestEnd:" + toString(i);
609 if (myConditions.count(cond) == 0) {
610 throw ProcessError("Missing condition '" + cond + errorSuffix);
611 }
612 }
613 if (phase->latestEnd == ovrd) {
614 const std::string cond = "latestEnd:" + toString(i);
615 if (myConditions.count(cond) == 0) {
616 throw ProcessError("Missing condition '" + cond + errorSuffix);
617 }
618 }
619 }
620}
621
622
623void
625 for (int i = 0; i < (int)myPhases.size(); i++) {
627 MSPhaseDefinition* phase = myPhases[i];
628 std::vector<int> nextPhases = phase->nextPhases;
629 if (nextPhases.size() == 0) {
630 nextPhases.push_back((i + 1) % (int)myPhases.size());
631 } else if (nextPhases.size() > 1) {
632 myHasMultiTarget = true;
633 }
634 for (int next : nextPhases) {
635 if (next >= 0 && next < (int)myPhases.size()) {
636 const MSPhaseDefinition* nextPhase = myPhases[next];
637 if (nextPhase->earlyTarget != "" || nextPhase->finalTarget != "") {
638 sr.enabled = true;
639 }
640 }
641 }
642 // simplifies later code
643 phase->nextPhases = nextPhases;
644 mySwitchingRules.push_back(sr);
645 }
646}
647
648
649void
651 // next -> target -> transitionTime starting from step
652 std::map<int, std::map<int, SUMOTime> > reached;
653 const std::vector<int>& next = myPhases[step]->nextPhases;
654 for (int n : next) {
655 findTargets(step, n, 0, reached[n]);
656 }
657 for (int target = 0; target < (int)myPhases.size(); target++) {
658 int bestNext = next[0];
659 SUMOTime bestTime = SUMOTime_MAX;
660 for (auto item : reached) {
661 auto it = item.second.find(target);
662 if (it != item.second.end()) {
663 SUMOTime transitionTime = it->second;
664 if (transitionTime < bestTime) {
665 bestTime = transitionTime;
666 bestNext = item.first;
667 }
668 }
669 }
670 if (bestTime != SUMOTime_MAX) {
671 myTargets[step][bestNext].push_back(target);
672 //std::cout << " myTargets step=" << step << " bestNext=" << bestNext << " target=" << target << "\n";
673 }
674 }
675}
676
677
678void
679MSActuatedTrafficLightLogic::findTargets(int origStep, int n, SUMOTime priorTransition, std::map<int, SUMOTime>& found) {
680 std::pair<int, SUMOTime> tDur = getTarget(n);
681 int target = tDur.first;
682 SUMOTime transitionTime = tDur.second + priorTransition;
683 //std::cout << " findTargets origStep=" << origStep << " n=" << n << " ptt=" << priorTransition << " target=" << target << " tt=" << transitionTime << "\n";
684 if (target == origStep) {
685 // full circle
686 //std::cout << " foundCircle\n";
687 return;
688 }
689 auto it = found.find(target);
690 if (it != found.end()) {
691 if (it->second <= transitionTime) {
692 //std::cout << " oldShorterTime=" << it->second << "\n";
693 // found the same target again
694 return;
695 } else {
696 //std::cout << " newShorterTime=" << it->second << "\n";
697 }
698 } else {
699 //std::cout << " newTarget\n";
700 }
701 found[target] = transitionTime;
702 //std::cout << " targetNext=" << toString(myPhases[target]->nextPhases) << "\n";
703 for (int n2 : myPhases[target]->nextPhases) {
704 findTargets(origStep, n2, transitionTime, found);
705 }
706}
707
708
709std::set<int>
711 std::set<int> result;
712 if (myHasMultiTarget) {
713 // find all phase that are the target green phase of a 'next' attribute
714 for (const MSPhaseDefinition* p : myPhases) {
715 for (int next : p->nextPhases) {
716 result.insert(getTarget(next).first);
717 }
718 }
719 }
720 return result;
721}
722
723
725MSActuatedTrafficLightLogic::getMinimumMinDuration(MSLane* lane, const std::set<int>& multiNextTargets) const {
726 SUMOTime result = std::numeric_limits<SUMOTime>::max();
727 for (int pI = 0; pI < (int)myPhases.size(); pI++) {
728 const MSPhaseDefinition* phase = myPhases[pI];
729 const std::string& state = phase->getState();
730 for (int i = 0; i < (int)state.size(); i++) {
731 if (state[i] == LINKSTATE_TL_GREEN_MAJOR || state[i] == LINKSTATE_TL_GREEN_MINOR) {
732 for (MSLane* cand : getLanesAt(i)) {
733 if (lane == cand) {
734 if (phase->isActuated()) {
735 result = MIN2(result, getMinDur(pI));
736 } else if (multiNextTargets.count(pI) != 0) {
737 result = MIN2(result, DEFAULT_STATIC_MINDUR);
738 }
739 }
740 }
741 }
742 }
743 }
744 return result;
745}
746
747bool
748MSActuatedTrafficLightLogic::hasMajor(const std::string& state, const LaneVector& lanes) const {
749 for (int i = 0; i < (int)state.size(); i++) {
750 if (state[i] == LINKSTATE_TL_GREEN_MAJOR) {
751 for (MSLane* cand : getLanesAt(i)) {
752 for (MSLane* lane : lanes) {
753 if (lane == cand) {
754 return true;
755 }
756 }
757 }
758 }
759 }
760 return false;
761}
762
763
764// ------------ Switching and setting current rows
765void
772
773
774void
777 for (InductLoopInfo& loopInfo : myInductLoops) {
778 loopInfo.loop->setVisible(false);
779 }
780}
781
782void
784 SUMOTime simStep, int step, SUMOTime stepDuration) {
785 // do not change timing if the phase changes
786 if (step >= 0 && step != myStep) {
787 myStep = step;
789 setTrafficLightSignals(simStep);
790 tlcontrol.get(getID()).executeOnSwitchActions();
791 } else if (step < 0) {
792 // TraCI requested new timing
794 mySwitchCommand = new SwitchCommand(tlcontrol, this, stepDuration + simStep);
796 mySwitchCommand, stepDuration + simStep);
797 myTraCISwitch = true;
798 }
799}
800
801
802void
803MSActuatedTrafficLightLogic::loadState(MSTLLogicControl& tlcontrol, SUMOTime t, int step, SUMOTime spentDuration, SUMOTime nextSwitch, SUMOTime /*timeInCycle*/, bool active) {
804 myAmActive = active;
805 const SUMOTime lastSwitch = t - spentDuration;
806 myStep = step;
807 myPhases[myStep]->myLastSwitch = lastSwitch;
809 mySwitchCommand = new SwitchCommand(tlcontrol, this, nextSwitch);
811 if (myAmActive) {
812 setTrafficLightSignals(lastSwitch);
813 }
814 tlcontrol.get(getID()).executeOnSwitchActions();
815}
816
817
820 // checks if the actual phase should be continued
821 // @note any vehicles which arrived during the previous phases which are now waiting between the detector and the stop line are not
822 // considere here. RiLSA recommends to set minDuration in a way that lets all vehicles pass the detector
825
826 if (myLinkGreenTimes.size() > 0) {
827 // constraints exist, record green time durations for each link
828 const std::string& state = getCurrentPhaseDef().getState();
829 SUMOTime lastDuration = SIMSTEP - myLastTrySwitchTime;
830 for (int i = 0; i < myNumLinks; i++) {
831 if (state[i] == 'G' || state[i] == 'g') {
832 myLinkGreenTimes[i] += lastDuration;
833 } else {
834 myLinkGreenTimes[i] = 0;
835 }
836 if (state[i] == 'r' || state[i] == 'u') {
837 myLinkRedTimes[i] += lastDuration;
838 } else {
839 myLinkRedTimes[i] = 0;
840 }
841 }
842 }
844 // decide the next phase
845 const bool multiTarget = myPhases[myStep]->nextPhases.size() > 1 && myPhases[myStep]->nextPhases.front() >= 0;
846 const int origStep = myStep;
847 int nextStep = myStep;
848 SUMOTime actDuration = now - myPhases[myStep]->myLastSwitch;
849
850 if (mySwitchingRules[myStep].enabled) {
851 const bool mustSwitch = MIN2(getMaxDur() - actDuration, getLatest()) <= 0;
852 nextStep = decideNextPhaseCustom(mustSwitch);
853 } else {
854 // default algorithm
855 const double detectionGap = gapControl();
856#ifdef DEBUG_PHASE_SELECTION
857 if (DEBUG_COND) {
858 std::cout << SIMTIME << " p=" << myStep
859 << " trySwitch dGap=" << (detectionGap == std::numeric_limits<double>::max() ? "inf" : toString(detectionGap))
860 << " multi=" << multiTarget << "\n";
861 }
862#endif
863 if (detectionGap < std::numeric_limits<double>::max() && !multiTarget && !myTraCISwitch) {
864 return duration(detectionGap);
865 }
866 if (multiTarget) {
867 nextStep = decideNextPhase();
868 } else {
869 if (myPhases[myStep]->nextPhases.size() == 1 && myPhases[myStep]->nextPhases.front() >= 0) {
870 nextStep = myPhases[myStep]->nextPhases.front();
871 } else {
872 nextStep = (myStep + 1) % (int)myPhases.size();
873 }
874 }
875 }
876
877 myTraCISwitch = false;
878 if (myLinkMinGreenTimes.size() > 0) {
879 SUMOTime linkMinDur = getLinkMinDuration(getTarget(nextStep).first);
880 if (linkMinDur > 0) {
881 // for multiTarget, the current phase must be extended but if another
882 // targer is chosen, earlier switching than linkMinDur is possible
883 return multiTarget ? TIME2STEPS(1) : linkMinDur;
884 }
885 }
886 myStep = nextStep;
887 assert(myStep <= (int)myPhases.size());
888 assert(myStep >= 0);
889 //stores the time the phase started
890 const SUMOTime prevStart = myPhases[myStep]->myLastSwitch;
891 if (myStep != origStep) {
892 myPhases[origStep]->myLastEnd = now;
893 myPhases[myStep]->myLastSwitch = now;
894 actDuration = 0;
895 }
896 // activate coloring
897 if ((myShowDetectors || myHasMultiTarget) && getCurrentPhaseDef().isGreenPhase()) {
898 for (InductLoopInfo* loopInfo : myInductLoopsForPhase[myStep]) {
899 //std::cout << SIMTIME << " p=" << myStep << " loopinfo=" << loopInfo->loop->getID() << " set lastGreen=" << STEPS2TIME(now) << "\n";
900 if (loopInfo->isJammed()) {
901 loopInfo->loop->setSpecialColor(&RGBColor::ORANGE);
902 } else {
903 loopInfo->loop->setSpecialColor(&RGBColor::GREEN);
904 }
905 loopInfo->lastGreenTime = now;
906 }
907 }
908 // set the next event
909#ifdef DEBUG_PHASE_SELECTION
910 if (DEBUG_COND) {
911 std::cout << SIMTIME << " tl=" << getID() << " p=" << myStep
912 << " nextTryMinDur=" << STEPS2TIME(getMinDur() - actDuration)
913 << " nextTryEarliest=" << STEPS2TIME(getEarliest(prevStart)) << "\n";
914 }
915#endif
916 SUMOTime minRetry = myStep != origStep ? 0 : TIME2STEPS(1);
917 return MAX3(minRetry, getMinDur() - actDuration, getEarliest(prevStart));
918}
919
920
921// ------------ "actuated" algorithm methods
923MSActuatedTrafficLightLogic::duration(const double detectionGap) const {
924 assert(getCurrentPhaseDef().isGreenPhase());
925 assert((int)myPhases.size() > myStep);
926 const SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
927 // ensure that minimum duration is kept
928 SUMOTime newDuration = getMinDur() - actDuration;
929 // try to let the last detected vehicle pass the intersection (duration must be positive)
930 newDuration = MAX3(newDuration, TIME2STEPS(myDetectorGap - detectionGap), SUMOTime(1));
931 // cut the decimal places to ensure that phases always have integer duration
932 if (newDuration % 1000 != 0) {
933 const SUMOTime totalDur = newDuration + actDuration;
934 newDuration = (totalDur / 1000 + 1) * 1000 - actDuration;
935 }
936 // ensure that the maximum duration is not exceeded
937 newDuration = MIN3(newDuration, getMaxDur() - actDuration, getLatest());
938 return newDuration;
939}
940
941
942double
944 //intergreen times should not be lengthend
945 assert((int)myPhases.size() > myStep);
946 double result = std::numeric_limits<double>::max();
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 seen = 0;
1033 int origStep = step;
1034 SUMOTime dur = 0;
1035
1036 // if step is a transition, find the upcoming green phase
1037 while (!myPhases[step]->isGreenPhase()) {
1038 seen += 1;
1039 dur += myPhases[step]->duration;
1040 if (myPhases[step]->nextPhases.size() > 0 && myPhases[step]->nextPhases.front() >= 0) {
1041 for (int next : myPhases[step]->nextPhases) {
1042 if (next != step) {
1043 step = next;
1044 break;
1045 }
1046 }
1047 } else {
1048 step = (step + 1) % (int)myPhases.size();
1049 }
1050 if (step == origStep || seen > (int)myPhases.size()) {
1051 WRITE_WARNING("At actuated tlLogic '" + getID() + "', infinite transition loop from phase " + toString(origStep));
1052 return std::make_pair(0, 0);
1053 }
1054 }
1055 return std::make_pair(step, dur);
1056}
1057
1058int
1060 MSInductLoop* loop = loopInfo.loop;
1061 const double actualGap = loop->getTimeSinceLastDetection();
1062 if ((actualGap < loopInfo.maxGap && !loopInfo.isJammed())
1063 || loopInfo.lastGreenTime < loop->getLastDetectionTime()) {
1064 SUMOTime inactiveTime = MSNet::getInstance()->getCurrentTimeStep() - loopInfo.lastGreenTime;
1065 // @note. Inactive time could also be tracked regardless of current activity (to increase robustness in case of detection failure
1066 if (inactiveTime > myInactiveThreshold) {
1067#ifdef DEBUG_PHASE_SELECTION
1068 if (DEBUG_COND) {
1069 std::cout << " loop=" << loop->getID() << " gap=" << loop->getTimeSinceLastDetection() << " lastGreen=" << STEPS2TIME(loopInfo.lastGreenTime)
1070 << " lastDetection=" << STEPS2TIME(loop->getLastDetectionTime()) << " inactive=" << STEPS2TIME(inactiveTime) << "\n";
1071 }
1072#endif
1073 return (int)STEPS2TIME(inactiveTime);
1074 } else {
1075 // give bonus to detectors that are currently served (if that phase can stil be extended)
1076 if (loopInfo.servedPhase[myStep]) {
1077 SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
1078 const bool canExtend = actDuration < getCurrentPhaseDef().maxDuration && getLatest() > 0;
1079#ifdef DEBUG_PHASE_SELECTION
1080 if (DEBUG_COND) {
1081 std::cout << " loop=" << loop->getID()
1082 << " actDuration=" << STEPS2TIME(actDuration)
1083 << " maxDur=" << STEPS2TIME(getCurrentPhaseDef().maxDuration)
1084 << " getLatest=" << STEPS2TIME(getLatest())
1085 << " canExtend=" << canExtend
1086 << "\n";
1087 }
1088#endif
1089 if (canExtend) {
1091 } else {
1092 return 0;
1093 }
1094 }
1095 return 1;
1096 }
1097 }
1098 return 0;
1099}
1100
1101int
1103 int result = 0;
1104 for (const InductLoopInfo* loopInfo : myInductLoopsForPhase[step]) {
1105 result += getDetectorPriority(*loopInfo);
1106 }
1107 if (myCrossingsForPhase.size() > 0) {
1108 for (const MSLink* crossingEntry : myCrossingsForPhase[step]) {
1109 auto* aPersons = crossingEntry->getApproachingPersons();
1110 if (aPersons != nullptr && aPersons->size() > 0) {
1111 result += DEFAULT_CROSSING_PRIORITY;
1112 }
1113 }
1114 }
1115 return result;
1116}
1117
1118
1119void
1121 myShowDetectors = show;
1122 for (InductLoopInfo& loopInfo : myInductLoops) {
1123 loopInfo.loop->setVisible(myShowDetectors);
1124 }
1125}
1126
1127
1128bool
1130 if (myLinkMaxGreenTimes.empty()) {
1131 return false;
1132 }
1133 for (int i = 0; i < myNumLinks; i++) {
1135 //std::cout << SIMTIME << " maxLinkDurationReached i=" << i << "\n";
1136 return true;
1137 }
1138 }
1139 return false;
1140}
1141
1142bool
1144 if (myLinkMaxGreenTimes.empty()) {
1145 return true;
1146 }
1147 const std::string& targetState = myPhases[target]->getState();
1148 for (int i = 0; i < myNumLinks; i++) {
1149 if (myLinkGreenTimes[i] >= myLinkMaxGreenTimes[i] && (
1150 targetState[i] == 'G' || targetState[i] == 'g')) {
1151 //std::cout << SIMTIME << " cannotExtendLinkGreen target=" << target << " i=" << i << "\n";
1152 return false;
1153 }
1154 }
1155 return true;
1156}
1157
1160 SUMOTime result = 0;
1161 if (target != myStep && myLinkMinGreenTimes.size() > 0) {
1162 const std::string& state = myPhases[myStep]->getState();
1163 const std::string& targetState = myPhases[target]->getState();
1164 for (int i = 0; i < myNumLinks; i++) {
1166 && (state[i] == 'G' || state[i] == 'g')
1167 && !(targetState[i] == 'G' || targetState[i] == 'g')) {
1168 result = MAX2(result, myLinkMinGreenTimes[i] - myLinkGreenTimes[i]);
1169 //std::cout << SIMTIME << " getLinkMinDuration myStep=" << myStep << " target=" << target << " i=" << i
1170 // << " greenTime=" << STEPS2TIME(myLinkGreenTimes[i]) << " min=" << STEPS2TIME(myLinkMinGreenTimes[i]) << " result=" << STEPS2TIME(result) << "\n";
1171 }
1172 }
1173 }
1174 return result;
1175}
1176
1177int
1179 for (int next : getCurrentPhaseDef().nextPhases) {
1180 const MSPhaseDefinition* phase = myPhases[next];
1181 const std::string& condition = mustSwitch ? phase->finalTarget : phase->earlyTarget;
1182#ifdef DEBUG_PHASE_SELECTION_CUSTOM
1183 if (DEBUG_COND) {
1184 std::cout << SIMTIME << " mustSwitch=" << mustSwitch << " cur=" << myStep << " next=" << next << " condition=" << condition
1185 << " eval=" << (condition == "" ? NAN : evalExpression(condition)) << "\n";
1186 }
1187#endif
1188 if (condition != "") {
1189 // backward compatibility if a user redefined DEFAULT_CONDITION
1190 if (condition == DEFAULT_CONDITION && myConditions.count(DEFAULT_CONDITION) == 0) {
1191 if (gapControl() == std::numeric_limits<double>::max()) {
1192 return next;
1193 }
1194 } else if (evalExpression(condition)) {
1195 return next;
1196 }
1197 }
1198 }
1199 return mustSwitch ? getCurrentPhaseDef().nextPhases.back() : myStep;
1200}
1201
1202
1203double
1204MSActuatedTrafficLightLogic::evalExpression(const std::string& condition) const {
1205 const size_t bracketOpen = condition.find('(');
1206 if (bracketOpen != std::string::npos) {
1207 // find matching closing bracket
1208 size_t bracketClose = std::string::npos;
1209 int open = 1;
1210 for (size_t i = bracketOpen + 1; i < condition.size(); i++) {
1211 if (condition[i] == '(') {
1212 open++;
1213 } else if (condition[i] == ')') {
1214 open--;
1215 if (open == 0) {
1216 bracketClose = i;
1217 break;
1218 }
1219 }
1220 }
1221 if (bracketClose == std::string::npos) {
1222 throw ProcessError(TLF("Unmatched parentheses in condition %'", condition));
1223 }
1224 std::string cond2 = condition;
1225 const std::string inBracket = condition.substr(bracketOpen + 1, bracketClose - bracketOpen - 1);
1226 double bracketVal = evalExpression(inBracket);
1227 cond2.replace(bracketOpen, bracketClose - bracketOpen + 1, toString(bracketVal));
1228 try {
1229 return evalExpression(cond2);
1230 } catch (ProcessError& e) {
1231 throw ProcessError(TLF("Error when evaluating expression '%':\n %", condition, e.what()));
1232 }
1233 }
1234 std::vector<std::string> tokens = StringTokenizer(condition).getVector();
1235 //std::cout << SIMTIME << " tokens(" << tokens.size() << ")=" << toString(tokens) << "\n";
1236 if (tokens.size() == 0) {
1237 throw ProcessError(TLF("Invalid empty condition '%'", condition));
1238 } else if (tokens.size() == 1) {
1239 try {
1240 return evalAtomicExpression(tokens[0]);
1241 } catch (ProcessError& e) {
1242 throw ProcessError(TLF("Error when evaluating expression '%':\n %", condition, e.what()));
1243 }
1244 } else if (tokens.size() == 2) {
1245 if (tokens[0] == "not") {
1246 try {
1247 return evalAtomicExpression(tokens[1]) == 0. ? 1. : 0.;
1248 } catch (ProcessError& e) {
1249 throw ProcessError(TLF("Error when evaluating expression '%':\n %", condition, e.what()));
1250 }
1251 } else {
1252 throw ProcessError(TLF("Unsupported condition '%'", condition));
1253 }
1254 } else if (tokens.size() == 3) {
1255 // infix expression
1256 const double a = evalAtomicExpression(tokens[0]);
1257 const double b = evalAtomicExpression(tokens[2]);
1258 const std::string& o = tokens[1];
1259 //std::cout << SIMTIME << " o=" << o << " a=" << a << " b=" << b << "\n";
1260 try {
1261 return evalTernaryExpression(a, o, b, condition);
1262 } catch (ProcessError& e) {
1263 throw ProcessError(TLF("Error when evaluating expression '%':\n %", condition, e.what()));
1264 }
1265 } else {
1266 const int iEnd = (int)tokens.size() - 1;
1267 for (const std::string& o : OPERATOR_PRECEDENCE) {
1268 for (int i = 1; i < iEnd; i++) {
1269 if (tokens[i] == o) {
1270 try {
1271 const double val = evalTernaryExpression(
1272 evalAtomicExpression(tokens[i - 1]), o,
1273 evalAtomicExpression(tokens[i + 1]), condition);
1274 std::vector<std::string> newTokens(tokens.begin(), tokens.begin() + (i - 1));
1275 newTokens.push_back(toString(val));
1276 newTokens.insert(newTokens.end(), tokens.begin() + (i + 2), tokens.end());
1277 return evalExpression(toString(newTokens));
1278 } catch (ProcessError& e) {
1279 throw ProcessError(TLF("Error when evaluating expression '%':\n %", condition, e.what()));
1280 }
1281 }
1282 }
1283 }
1284 throw ProcessError(TLF("Parsing expressions with % elements ('%') is not supported", toString(tokens.size()), condition));
1285 }
1286 return true;
1287}
1288
1289double
1290MSActuatedTrafficLightLogic::evalTernaryExpression(double a, const std::string& o, double b, const std::string& condition) const {
1291 if (o == "=" || o == "==") {
1292 return (double)(a == b);
1293 } else if (o == "<") {
1294 return (double)(a < b);
1295 } else if (o == ">") {
1296 return (double)(a > b);
1297 } else if (o == "<=") {
1298 return (double)(a <= b);
1299 } else if (o == ">=") {
1300 return (double)(a >= b);
1301 } else if (o == "!=") {
1302 return (double)(a != b);
1303 } else if (o == "or" || o == "||") {
1304 return (double)(a || b);
1305 } else if (o == "and" || o == "&&") {
1306 return (double)(a && b);
1307 } else if (o == "+") {
1308 return a + b;
1309 } else if (o == "-") {
1310 return a - b;
1311 } else if (o == "*") {
1312 return a * b;
1313 } else if (o == "/") {
1314 if (b == 0) {
1315 WRITE_ERRORF(TL("Division by 0 in condition '%'"), condition);
1316 return 0;
1317 }
1318 return a / b;
1319 } else if (o == "%") {
1320 return fmod(a, b);
1321 } else if (o == "**" || o == "^") {
1322 return pow(a, b);
1323 } else {
1324 throw ProcessError(TLF("Unsupported operator '%' in condition '%'", o, condition));
1325 }
1326}
1327
1328double
1329MSActuatedTrafficLightLogic::evalCustomFunction(const std::string& fun, const std::string& arg) const {
1330 std::vector<std::string> args = StringTokenizer(arg, ",").getVector();
1331 const Function& f = myFunctions.find(fun)->second;
1332 if ((int)args.size() != f.nArgs) {
1333 throw ProcessError(TLF("Function '%' requires % arguments but % were given", fun, toString(f.nArgs), toString(args.size())));
1334 }
1335 std::vector<double> args2;
1336 for (auto a : args) {
1337 args2.push_back(evalExpression(a));
1338 }
1339 myStack.push_back(myStack.back());
1340 myStack.back()["$0"] = 0;
1341 for (int i = 0; i < (int)args2.size(); i++) {
1342 myStack.back()["$" + toString(i + 1)] = args2[i];
1343 }
1344 try {
1345 ConditionMap empty;
1347 } catch (ProcessError& e) {
1348 throw ProcessError(TLF("Error when evaluating function '%' with args '%' (%)", fun, joinToString(args2, ","), e.what()));
1349 }
1350 double result = myStack.back()["$0"];
1351 myStack.pop_back();
1352 return result;
1353}
1354
1355
1356void
1357MSActuatedTrafficLightLogic::executeAssignments(const AssignmentMap& assignments, ConditionMap& conditions, const ConditionMap& forbidden) const {
1358 for (const auto& assignment : assignments) {
1359 if (evalExpression(std::get<1>(assignment))) {
1360 const std::string& id = std::get<0>(assignment);
1361 const double val = evalExpression(std::get<2>(assignment));
1362 ConditionMap::iterator it = conditions.find(id);
1363 if (it != conditions.end()) {
1364 it->second = toString(val);
1365 } else if (forbidden.find(id) != forbidden.end()) {
1366 throw ProcessError(TLF("Modifying global condition '%' is forbidden", id));
1367 } else {
1368 myStack.back()[id] = val;
1369 }
1370 }
1371 }
1372}
1373
1374
1375double
1377 if (expr.size() == 0) {
1378 throw ProcessError(TL("Invalid empty expression"));
1379 } else if (expr[0] == '!') {
1380 return evalAtomicExpression(expr.substr(1)) == 0. ? 1. : 0.;
1381 } else if (expr[0] == '-') {
1382 return -evalAtomicExpression(expr.substr(1));
1383 } else {
1384 // check for 'operator:'
1385 const size_t pos = expr.find(':');
1386 if (pos == std::string::npos) {
1387 auto it = myConditions.find(expr);
1388 if (it != myConditions.end()) {
1389 // symbol lookup
1390 return evalExpression(it->second);
1391 } else {
1392 // look at stack
1393 auto it2 = myStack.back().find(expr);
1394 if (it2 != myStack.back().end()) {
1395 return it2->second;
1396 }
1397 // must be a number
1398 return StringUtils::toDouble(expr);
1399 }
1400 } else {
1401 const std::string fun = expr.substr(0, pos);
1402 const std::string arg = expr.substr(pos + 1);
1403 if (fun == "z") {
1404 return retrieveDetExpression<MSInductLoop, SUMO_TAG_INDUCTION_LOOP>(arg, expr, true)->getTimeSinceLastDetection();
1405 } else if (fun == "a") {
1406 try {
1407 return retrieveDetExpression<MSInductLoop, SUMO_TAG_INDUCTION_LOOP>(arg, expr, true)->getTimeSinceLastDetection() == 0;
1408 } catch (ProcessError&) {
1409 return retrieveDetExpression<MSE2Collector, SUMO_TAG_LANE_AREA_DETECTOR>(arg, expr, true)->getCurrentVehicleNumber();
1410 }
1411 } else if (fun == "w") {
1412 try {
1413 return retrieveDetExpression<MSInductLoop, SUMO_TAG_INDUCTION_LOOP>(arg, expr, true)->getOccupancyTime();
1414 } catch (ProcessError&) {
1415 return retrieveDetExpression<MSE2Collector, SUMO_TAG_LANE_AREA_DETECTOR>(arg, expr, true)->getCurrentJamDuration();
1416 }
1417 } else if (fun == "d") {
1418 try {
1419 return retrieveDetExpression<MSInductLoop, SUMO_TAG_INDUCTION_LOOP>(arg, expr, true)->getArrivalDelay();
1420 } catch (ProcessError&) {
1421 return retrieveDetExpression<MSE2Collector, SUMO_TAG_LANE_AREA_DETECTOR>(arg, expr, true)->getArrivalDelay();
1422 }
1423 } else if (fun == "g" || fun == "r") {
1424 try {
1425 int linkIndex = StringUtils::toInt(arg);
1426 if (linkIndex >= 0 && linkIndex < myNumLinks) {
1427 const std::vector<SUMOTime>& times = fun == "g" ? myLinkGreenTimes : myLinkRedTimes;
1428 if (times.empty()) {
1429 return 0;
1430 }
1432 // times are only updated at the start of a phase where
1433 // switching is possible (i.e. not during minDur).
1434 // If somebody is looking at those values in the tracker
1435 // this would be confusing
1436 const LinkState ls = getCurrentPhaseDef().getSignalState(linkIndex);
1437 if ((fun == "g" && (ls == LINKSTATE_TL_GREEN_MAJOR || ls == LINKSTATE_TL_GREEN_MINOR))
1438 || (fun == "r" && (ls == LINKSTATE_TL_RED || ls == LINKSTATE_TL_REDYELLOW))) {
1439 const SUMOTime currentGreen = SIMSTEP - myLastTrySwitchTime;
1440 return STEPS2TIME(times[linkIndex] + currentGreen);
1441 } else {
1442 return 0;
1443 }
1444 } else {
1445 return STEPS2TIME(times[linkIndex]);
1446 }
1447 }
1448 } catch (NumberFormatException&) { }
1449 throw ProcessError(TLF("Invalid link index '%' in expression '%'", arg, expr));
1450 } else if (fun == "p") {
1451 try {
1452 int linkIndex = StringUtils::toInt(arg);
1453 if (linkIndex >= 0 && linkIndex < myNumLinks) {
1454 double approachingPersons = 0;
1455 for (const MSLink* link : getLinksAt(linkIndex)) {
1456 auto* aPersons = link->getApproachingPersons();
1457 if (aPersons != nullptr) {
1458 approachingPersons += (double)aPersons->size();
1459 }
1460 }
1461 return approachingPersons;
1462 }
1463 } catch (NumberFormatException&) { }
1464 throw ProcessError(TLF("Invalid link index '%' in expression '%'", arg, expr));
1465 } else if (fun == "c") {
1466 return STEPS2TIME(getTimeInCycle());
1467 } else {
1468 if (myFunctions.find(fun) == myFunctions.end()) {
1469 throw ProcessError(TLF("Unsupported function '%' in expression '%'", fun, expr));
1470 }
1471 return evalCustomFunction(fun, arg);
1472 }
1473 }
1474 }
1475}
1476
1477
1478std::map<std::string, double>
1480 std::map<std::string, double> result;
1481 for (auto li : myInductLoops) {
1482 result[li.loop->getID()] = li.loop->getOccupancy() > 0 ? 1 : 0;
1483 }
1484 for (auto loop : myExtraLoops) {
1485 result[loop->getID()] = loop->getOccupancy() > 0 ? 1 : 0;
1486 }
1487 for (auto loop : myExtraE2) {
1488 result[loop->getID()] = loop->getCurrentVehicleNumber();
1489 }
1490 return result;
1491}
1492
1493double
1494MSActuatedTrafficLightLogic::getDetectorState(const std::string laneID) const {
1495 double result = 0.0;
1496 for (auto li : myInductLoops) {
1497 if (li.lane->getID() == laneID) {
1498 result = li.loop->getOccupancy() > 0 ? 1 : 0;
1499 break;
1500 }
1501 }
1502 return result;
1503}
1504
1505std::map<std::string, double>
1507 std::map<std::string, double> result;
1508 for (auto item : myConditions) {
1509 if (myListedConditions.count(item.first) != 0) {
1510 try {
1511 result[item.first] = evalExpression(item.second);
1512 } catch (ProcessError& e) {
1513 WRITE_ERRORF(TL("Error when retrieving conditions '%' for tlLogic '%' (%)"), item.first, getID(), e.what());
1514 }
1515 }
1516 }
1517 return result;
1518}
1519
1520const std::string
1521MSActuatedTrafficLightLogic::getParameter(const std::string& key, const std::string defaultValue) const {
1522 if (StringUtils::startsWith(key, "condition.")) {
1523 const std::string cond = key.substr(10);
1524 auto it = myConditions.find(cond);
1525 if (it != myConditions.end()) {
1526 return toString(evalExpression(it->second));
1527 } else {
1528 throw InvalidArgument(TLF("Unknown condition '%' for actuated traffic light '%'", cond, getID()));
1529 }
1530 } else {
1531 return MSSimpleTrafficLightLogic::getParameter(key, defaultValue);
1532 }
1533}
1534
1535void
1536MSActuatedTrafficLightLogic::setParameter(const std::string& key, const std::string& value) {
1537 // some pre-defined parameters can be updated at runtime
1538 if (key == "detector-gap" || key == "passing-time" || key == "file" || key == "freq" || key == "vTypes"
1539 || key == "build-all-detectors"
1540 || StringUtils::startsWith(key, "linkMaxDur")
1541 || StringUtils::startsWith(key, "linkMinDur")) {
1542 throw InvalidArgument(key + " cannot be changed dynamically for actuated traffic light '" + getID() + "'");
1543 } else if (key == "max-gap") {
1545 // overwrite custom values
1546 for (InductLoopInfo& loopInfo : myInductLoops) {
1547 loopInfo.maxGap = myMaxGap;
1548 }
1549 Parameterised::setParameter(key, value);
1550 } else if (StringUtils::startsWith(key, "max-gap:")) {
1551 const std::string laneID = key.substr(8);
1552 for (InductLoopInfo& loopInfo : myInductLoops) {
1553 if (loopInfo.lane->getID() == laneID) {
1554 loopInfo.maxGap = StringUtils::toDouble(value);
1555 Parameterised::setParameter(key, value);
1556 return;
1557 }
1558 }
1559 throw InvalidArgument(TLF("Invalid lane '%' in key '%' for actuated traffic light '%'", laneID, key, getID()));
1560 } else if (key == "jam-threshold") {
1562 // overwrite custom values
1563 for (InductLoopInfo& loopInfo : myInductLoops) {
1564 loopInfo.jamThreshold = myJamThreshold;
1565 }
1566 Parameterised::setParameter(key, value);
1567 } else if (StringUtils::startsWith(key, "jam-threshold:")) {
1568 const std::string laneID = key.substr(14);
1569 for (InductLoopInfo& loopInfo : myInductLoops) {
1570 if (loopInfo.lane->getID() == laneID) {
1571 loopInfo.jamThreshold = StringUtils::toDouble(value);
1572 Parameterised::setParameter(key, value);
1573 return;
1574 }
1575 }
1576 throw InvalidArgument(TLF("Invalid lane '%' in key '%' for actuated traffic light '%'", laneID, key, getID()));
1577 } else if (key == "show-detectors") {
1579 Parameterised::setParameter(key, value);
1580 for (InductLoopInfo& loopInfo : myInductLoops) {
1581 loopInfo.loop->setVisible(myShowDetectors);
1582 }
1583 } else if (key == "inactive-threshold") {
1585 Parameterised::setParameter(key, value);
1586 } else {
1588 }
1589}
1590
1591
1592/****************************************************************************/
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:287
#define WRITE_ERRORF(...)
Definition MsgHandler.h:296
#define WRITE_WARNING(msg)
Definition MsgHandler.h:286
#define TL(string)
Definition MsgHandler.h:304
#define TLF(string,...)
Definition MsgHandler.h:306
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition SUMOTime.cpp:47
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:107
#define STEPS2TIME(x)
Definition SUMOTime.h:58
#define SIMSTEP
Definition SUMOTime.h:69
constexpr SUMOTime TIME2STEPS(double x)
Definition SUMOTime.h:60
#define SUMOTime_MAX
Definition SUMOTime.h:34
#define SIMTIME
Definition SUMOTime.h:70
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:93
T MIN2(T a, T b)
Definition StdDefs.h:80
T MAX2(T a, T b)
Definition StdDefs.h:86
T MAX3(T a, T b, T c)
Definition StdDefs.h:100
std::string joinNamedToString(const std::set< T *, C > &ns, const T_BETWEEN &between)
Definition ToString.h:374
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition ToString.h:322
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition ToString.h:57
static std::string checkForRelativity(const std::string &filename, const std::string &basePath)
Returns the path from a configuration so that it is accessible 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.
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 loadState(MSTLLogicControl &tlcontrol, SUMOTime t, int step, SUMOTime spentDuration, SUMOTime nextSwitch, SUMOTime timeInCycle, bool active) override
restores the tls state, including the start of the current phase
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:78
double getSpeedLimit() const
Returns the speed limit of the edge @caution The speed limit of the first lane is returned; should pr...
Definition MSEdge.cpp:1235
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
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:984
double getLength() const
Returns the lane's length.
Definition MSLane.h:632
MSLane * getLogicalPredecessorLane() const
get the most likely predecessor lane (sorted using by_connections_to_sorter). The result is cached in...
Definition MSLane.cpp:3271
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:750
MSDetectorControl & getDetectorControl()
Returns the detector control.
Definition MSNet.h:465
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:201
MSEventControl * getBeginOfTimestepEvents()
Returns the event control for events executed at the begin of a time step.
Definition MSNet.h:495
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:334
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.
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 myAmActive
whether the current program is active
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, bool forceMicro=false)
Creates an instance of an e1 detector using the given values.
const std::string & getID() const
Returns the id.
Definition Named.h:73
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:210
static const RGBColor GREEN
Definition RGBColor.h:205
static const RGBColor RED
named colors
Definition RGBColor.h:204
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