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