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