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));
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, bool active) {
803 myAmActive = active;
804 const SUMOTime lastSwitch = t - spentDuration;
805 myStep = step;
806 myPhases[myStep]->myLastSwitch = lastSwitch;
807 const SUMOTime nextSwitch = t + getPhase(step).minDuration - spentDuration;
809 mySwitchCommand = new SwitchCommand(tlcontrol, this, nextSwitch);
811 if (myAmActive) {
812 setTrafficLightSignals(lastSwitch);
813 }
814 tlcontrol.get(getID()).executeOnSwitchActions();
815}
816
817
820 // checks if the actual phase should be continued
821 // @note any vehicles which arrived during the previous phases which are now waiting between the detector and the stop line are not
822 // considere here. RiLSA recommends to set minDuration in a way that lets all vehicles pass the detector
825
826 if (myLinkGreenTimes.size() > 0) {
827 // constraints exist, record green time durations for each link
828 const std::string& state = getCurrentPhaseDef().getState();
829 SUMOTime lastDuration = SIMSTEP - myLastTrySwitchTime;
830 for (int i = 0; i < myNumLinks; i++) {
831 if (state[i] == 'G' || state[i] == 'g') {
832 myLinkGreenTimes[i] += lastDuration;
833 } else {
834 myLinkGreenTimes[i] = 0;
835 }
836 if (state[i] == 'r' || state[i] == 'u') {
837 myLinkRedTimes[i] += lastDuration;
838 } else {
839 myLinkRedTimes[i] = 0;
840 }
841 }
842 }
844 // decide the next phase
845 const bool multiTarget = myPhases[myStep]->nextPhases.size() > 1 && myPhases[myStep]->nextPhases.front() >= 0;
846 const int origStep = myStep;
847 int nextStep = myStep;
848 SUMOTime actDuration = now - myPhases[myStep]->myLastSwitch;
849
850 if (mySwitchingRules[myStep].enabled) {
851 const bool mustSwitch = MIN2(getMaxDur() - actDuration, getLatest()) <= 0;
852 nextStep = decideNextPhaseCustom(mustSwitch);
853 } else {
854 // default algorithm
855 const double detectionGap = gapControl();
856#ifdef DEBUG_PHASE_SELECTION
857 if (DEBUG_COND) {
858 std::cout << SIMTIME << " p=" << myStep
859 << " trySwitch dGap=" << (detectionGap == std::numeric_limits<double>::max() ? "inf" : toString(detectionGap))
860 << " multi=" << multiTarget << "\n";
861 }
862#endif
863 if (detectionGap < std::numeric_limits<double>::max() && !multiTarget && !myTraCISwitch) {
864 return duration(detectionGap);
865 }
866 if (multiTarget) {
867 nextStep = decideNextPhase();
868 } else {
869 if (myPhases[myStep]->nextPhases.size() == 1 && myPhases[myStep]->nextPhases.front() >= 0) {
870 nextStep = myPhases[myStep]->nextPhases.front();
871 } else {
872 nextStep = (myStep + 1) % (int)myPhases.size();
873 }
874 }
875 }
876
877 myTraCISwitch = false;
878 if (myLinkMinGreenTimes.size() > 0) {
879 SUMOTime linkMinDur = getLinkMinDuration(getTarget(nextStep).first);
880 if (linkMinDur > 0) {
881 // for multiTarget, the current phase must be extended but if another
882 // targer is chosen, earlier switching than linkMinDur is possible
883 return multiTarget ? TIME2STEPS(1) : linkMinDur;
884 }
885 }
886 myStep = nextStep;
887 assert(myStep <= (int)myPhases.size());
888 assert(myStep >= 0);
889 //stores the time the phase started
890 const SUMOTime prevStart = myPhases[myStep]->myLastSwitch;
891 if (myStep != origStep) {
892 myPhases[origStep]->myLastEnd = now;
893 myPhases[myStep]->myLastSwitch = now;
894 actDuration = 0;
895 }
896 // activate coloring
897 if ((myShowDetectors || myHasMultiTarget) && getCurrentPhaseDef().isGreenPhase()) {
898 for (InductLoopInfo* loopInfo : myInductLoopsForPhase[myStep]) {
899 //std::cout << SIMTIME << " p=" << myStep << " loopinfo=" << loopInfo->loop->getID() << " set lastGreen=" << STEPS2TIME(now) << "\n";
900 if (loopInfo->isJammed()) {
901 loopInfo->loop->setSpecialColor(&RGBColor::ORANGE);
902 } else {
903 loopInfo->loop->setSpecialColor(&RGBColor::GREEN);
904 }
905 loopInfo->lastGreenTime = now;
906 }
907 }
908 // set the next event
909#ifdef DEBUG_PHASE_SELECTION
910 if (DEBUG_COND) {
911 std::cout << SIMTIME << " tl=" << getID() << " p=" << myStep
912 << " nextTryMinDur=" << STEPS2TIME(getMinDur() - actDuration)
913 << " nextTryEarliest=" << STEPS2TIME(getEarliest(prevStart)) << "\n";
914 }
915#endif
916 SUMOTime minRetry = myStep != origStep ? 0 : TIME2STEPS(1);
917 return MAX3(minRetry, getMinDur() - actDuration, getEarliest(prevStart));
918}
919
920
921// ------------ "actuated" algorithm methods
923MSActuatedTrafficLightLogic::duration(const double detectionGap) const {
924 assert(getCurrentPhaseDef().isGreenPhase());
925 assert((int)myPhases.size() > myStep);
926 const SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
927 // ensure that minimum duration is kept
928 SUMOTime newDuration = getMinDur() - actDuration;
929 // try to let the last detected vehicle pass the intersection (duration must be positive)
930 newDuration = MAX3(newDuration, TIME2STEPS(myDetectorGap - detectionGap), SUMOTime(1));
931 // cut the decimal places to ensure that phases always have integer duration
932 if (newDuration % 1000 != 0) {
933 const SUMOTime totalDur = newDuration + actDuration;
934 newDuration = (totalDur / 1000 + 1) * 1000 - actDuration;
935 }
936 // ensure that the maximum duration is not exceeded
937 newDuration = MIN3(newDuration, getMaxDur() - actDuration, getLatest());
938 return newDuration;
939}
940
941
942double
944 //intergreen times should not be lengthend
945 assert((int)myPhases.size() > myStep);
946 double result = std::numeric_limits<double>::max();
948 return result;
949 }
950 // switch off active colors
951 if (myShowDetectors) {
952 for (InductLoopInfo& loopInfo : myInductLoops) {
953 if (loopInfo.lastGreenTime < loopInfo.loop->getLastDetectionTime()) {
954 loopInfo.loop->setSpecialColor(&RGBColor::RED);
955 } else {
956 loopInfo.loop->setSpecialColor(nullptr);
957 }
958 }
959 }
961 return result; // end current phase
962 }
963
964 // Checks, if the maxDuration is kept. No phase should last longer than maxDuration.
965 SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
966 if (actDuration >= getCurrentPhaseDef().maxDuration || maxLinkDurationReached() || getLatest() == 0) {
967#ifdef DEBUG_PHASE_SELECTION
968 if (DEBUG_COND) {
969 std::cout << SIMTIME << " actDuration=" << STEPS2TIME(actDuration) << " maxDur=" << STEPS2TIME(getCurrentPhaseDef().maxDuration)
970 << " maxLinkDurationReached=" << maxLinkDurationReached() << " latest=" << STEPS2TIME(getLatest()) << "\n";
971 }
972#endif
973 return result; // end current phase
974 }
975
976 // now the gapcontrol starts
977 for (InductLoopInfo* loopInfo : myInductLoopsForPhase[myStep]) {
978 MSInductLoop* loop = loopInfo->loop;
979 if (loopInfo->isJammed()) {
980 loopInfo->loop->setSpecialColor(&RGBColor::ORANGE);
981 } else {
982 loopInfo->loop->setSpecialColor(&RGBColor::GREEN);
983 }
984 const double actualGap = loop->getTimeSinceLastDetection();
985 if (actualGap < loopInfo->maxGap && !loopInfo->isJammed()) {
986 result = MIN2(result, actualGap);
987 }
988 }
989 return result;
990}
991
992int
994 const auto& cands = myPhases[myStep]->nextPhases;
995 // decide by priority
996 // first target is the default when there is no traffic
997 // @note: to keep the current phase, even when there is no traffic, it must be added to 'next' explicitly
998 int result = cands.front();
999 int maxPrio = 0;
1000 SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
1001 const bool canExtend = actDuration < getCurrentPhaseDef().maxDuration && !maxLinkDurationReached() && getLatest() > 0;
1002 if (canExtend) {
1003 // consider keeping the current phase until maxDur is reached
1004 // (only when there is still traffic in that phase)
1005 int currentPrio = getPhasePriority(myStep);
1006#ifdef DEBUG_PHASE_SELECTION
1007 std::cout << SIMTIME << " p=" << myStep << " loops=" << myInductLoopsForPhase[myStep].size() << " currentPrio=" << currentPrio << "\n";
1008#endif
1009 if (currentPrio > maxPrio) {
1010 result = myStep;
1011 maxPrio = currentPrio;
1012 }
1013 }
1014 for (int step : cands) {
1015 int prio = 0;
1016 for (int target : myTargets[myStep][step]) {
1017 prio += getPhasePriority(target);
1018#ifdef DEBUG_PHASE_SELECTION
1019 if (DEBUG_COND) {
1020 std::cout << SIMTIME << " p=" << myStep << " step=" << step << " target=" << target << " loops=" << myInductLoopsForPhase[target].size() << " prio=" << prio << "\n";
1021 }
1022#endif
1023 }
1024 if (prio > maxPrio && canExtendLinkGreen(getTarget(step).first)) {
1025 maxPrio = prio;
1026 result = step;
1027 }
1028 }
1029 return result;
1030}
1031
1032
1033std::pair<int, SUMOTime>
1035 int seen = 0;
1036 int origStep = step;
1037 SUMOTime dur = 0;
1038
1039 // if step is a transition, find the upcoming green phase
1040 while (!myPhases[step]->isGreenPhase()) {
1041 seen += 1;
1042 dur += myPhases[step]->duration;
1043 if (myPhases[step]->nextPhases.size() > 0 && myPhases[step]->nextPhases.front() >= 0) {
1044 for (int next : myPhases[step]->nextPhases) {
1045 if (next != step) {
1046 step = next;
1047 break;
1048 }
1049 }
1050 } else {
1051 step = (step + 1) % (int)myPhases.size();
1052 }
1053 if (step == origStep || seen > (int)myPhases.size()) {
1054 WRITE_WARNING("At actuated tlLogic '" + getID() + "', infinite transition loop from phase " + toString(origStep));
1055 return std::make_pair(0, 0);
1056 }
1057 }
1058 return std::make_pair(step, dur);
1059}
1060
1061int
1063 MSInductLoop* loop = loopInfo.loop;
1064 const double actualGap = loop->getTimeSinceLastDetection();
1065 if ((actualGap < loopInfo.maxGap && !loopInfo.isJammed())
1066 || loopInfo.lastGreenTime < loop->getLastDetectionTime()) {
1067 SUMOTime inactiveTime = MSNet::getInstance()->getCurrentTimeStep() - loopInfo.lastGreenTime;
1068 // @note. Inactive time could also be tracked regardless of current activity (to increase robustness in case of detection failure
1069 if (inactiveTime > myInactiveThreshold) {
1070#ifdef DEBUG_PHASE_SELECTION
1071 if (DEBUG_COND) {
1072 std::cout << " loop=" << loop->getID() << " gap=" << loop->getTimeSinceLastDetection() << " lastGreen=" << STEPS2TIME(loopInfo.lastGreenTime)
1073 << " lastDetection=" << STEPS2TIME(loop->getLastDetectionTime()) << " inactive=" << STEPS2TIME(inactiveTime) << "\n";
1074 }
1075#endif
1076 return (int)STEPS2TIME(inactiveTime);
1077 } else {
1078 // give bonus to detectors that are currently served (if that phase can stil be extended)
1079 if (loopInfo.servedPhase[myStep]) {
1080 SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
1081 const bool canExtend = actDuration < getCurrentPhaseDef().maxDuration && getLatest() > 0;
1082#ifdef DEBUG_PHASE_SELECTION
1083 if (DEBUG_COND) {
1084 std::cout << " loop=" << loop->getID()
1085 << " actDuration=" << STEPS2TIME(actDuration)
1086 << " maxDur=" << STEPS2TIME(getCurrentPhaseDef().maxDuration)
1087 << " getLatest=" << STEPS2TIME(getLatest())
1088 << " canExtend=" << canExtend
1089 << "\n";
1090 }
1091#endif
1092 if (canExtend) {
1094 } else {
1095 return 0;
1096 }
1097 }
1098 return 1;
1099 }
1100 }
1101 return 0;
1102}
1103
1104int
1106 int result = 0;
1107 for (const InductLoopInfo* loopInfo : myInductLoopsForPhase[step]) {
1108 result += getDetectorPriority(*loopInfo);
1109 }
1110 if (myCrossingsForPhase.size() > 0) {
1111 for (const MSLink* crossingEntry : myCrossingsForPhase[step]) {
1112 auto* aPersons = crossingEntry->getApproachingPersons();
1113 if (aPersons != nullptr && aPersons->size() > 0) {
1114 result += DEFAULT_CROSSING_PRIORITY;
1115 }
1116 }
1117 }
1118 return result;
1119}
1120
1121
1122void
1124 myShowDetectors = show;
1125 for (InductLoopInfo& loopInfo : myInductLoops) {
1126 loopInfo.loop->setVisible(myShowDetectors);
1127 }
1128}
1129
1130
1131bool
1133 if (myLinkMaxGreenTimes.empty()) {
1134 return false;
1135 }
1136 for (int i = 0; i < myNumLinks; i++) {
1138 //std::cout << SIMTIME << " maxLinkDurationReached i=" << i << "\n";
1139 return true;
1140 }
1141 }
1142 return false;
1143}
1144
1145bool
1147 if (myLinkMaxGreenTimes.empty()) {
1148 return true;
1149 }
1150 const std::string& targetState = myPhases[target]->getState();
1151 for (int i = 0; i < myNumLinks; i++) {
1152 if (myLinkGreenTimes[i] >= myLinkMaxGreenTimes[i] && (
1153 targetState[i] == 'G' || targetState[i] == 'g')) {
1154 //std::cout << SIMTIME << " cannotExtendLinkGreen target=" << target << " i=" << i << "\n";
1155 return false;
1156 }
1157 }
1158 return true;
1159}
1160
1163 SUMOTime result = 0;
1164 if (target != myStep && myLinkMinGreenTimes.size() > 0) {
1165 const std::string& state = myPhases[myStep]->getState();
1166 const std::string& targetState = myPhases[target]->getState();
1167 for (int i = 0; i < myNumLinks; i++) {
1169 && (state[i] == 'G' || state[i] == 'g')
1170 && !(targetState[i] == 'G' || targetState[i] == 'g')) {
1171 result = MAX2(result, myLinkMinGreenTimes[i] - myLinkGreenTimes[i]);
1172 //std::cout << SIMTIME << " getLinkMinDuration myStep=" << myStep << " target=" << target << " i=" << i
1173 // << " greenTime=" << STEPS2TIME(myLinkGreenTimes[i]) << " min=" << STEPS2TIME(myLinkMinGreenTimes[i]) << " result=" << STEPS2TIME(result) << "\n";
1174 }
1175 }
1176 }
1177 return result;
1178}
1179
1180int
1182 for (int next : getCurrentPhaseDef().nextPhases) {
1183 const MSPhaseDefinition* phase = myPhases[next];
1184 const std::string& condition = mustSwitch ? phase->finalTarget : phase->earlyTarget;
1185#ifdef DEBUG_PHASE_SELECTION_CUSTOM
1186 if (DEBUG_COND) {
1187 std::cout << SIMTIME << " mustSwitch=" << mustSwitch << " cur=" << myStep << " next=" << next << " condition=" << condition
1188 << " eval=" << (condition == "" ? NAN : evalExpression(condition)) << "\n";
1189 }
1190#endif
1191 if (condition != "") {
1192 // backward compatibility if a user redefined DEFAULT_CONDITION
1193 if (condition == DEFAULT_CONDITION && myConditions.count(DEFAULT_CONDITION) == 0) {
1194 if (gapControl() == std::numeric_limits<double>::max()) {
1195 return next;
1196 }
1197 } else if (evalExpression(condition)) {
1198 return next;
1199 }
1200 }
1201 }
1202 return mustSwitch ? getCurrentPhaseDef().nextPhases.back() : myStep;
1203}
1204
1205
1206double
1207MSActuatedTrafficLightLogic::evalExpression(const std::string& condition) const {
1208 const size_t bracketOpen = condition.find('(');
1209 if (bracketOpen != std::string::npos) {
1210 // find matching closing bracket
1211 size_t bracketClose = std::string::npos;
1212 int open = 1;
1213 for (size_t i = bracketOpen + 1; i < condition.size(); i++) {
1214 if (condition[i] == '(') {
1215 open++;
1216 } else if (condition[i] == ')') {
1217 open--;
1218 if (open == 0) {
1219 bracketClose = i;
1220 break;
1221 }
1222 }
1223 }
1224 if (bracketClose == std::string::npos) {
1225 throw ProcessError(TLF("Unmatched parentheses in condition %'", condition));
1226 }
1227 std::string cond2 = condition;
1228 const std::string inBracket = condition.substr(bracketOpen + 1, bracketClose - bracketOpen - 1);
1229 double bracketVal = evalExpression(inBracket);
1230 cond2.replace(bracketOpen, bracketClose - bracketOpen + 1, toString(bracketVal));
1231 try {
1232 return evalExpression(cond2);
1233 } catch (ProcessError& e) {
1234 throw ProcessError(TLF("Error when evaluating expression '%':\n %", condition, e.what()));
1235 }
1236 }
1237 std::vector<std::string> tokens = StringTokenizer(condition).getVector();
1238 //std::cout << SIMTIME << " tokens(" << tokens.size() << ")=" << toString(tokens) << "\n";
1239 if (tokens.size() == 0) {
1240 throw ProcessError(TLF("Invalid empty condition '%'", condition));
1241 } else if (tokens.size() == 1) {
1242 try {
1243 return evalAtomicExpression(tokens[0]);
1244 } catch (ProcessError& e) {
1245 throw ProcessError(TLF("Error when evaluating expression '%':\n %", condition, e.what()));
1246 }
1247 } else if (tokens.size() == 2) {
1248 if (tokens[0] == "not") {
1249 try {
1250 return evalAtomicExpression(tokens[1]) == 0. ? 1. : 0.;
1251 } catch (ProcessError& e) {
1252 throw ProcessError(TLF("Error when evaluating expression '%':\n %", condition, e.what()));
1253 }
1254 } else {
1255 throw ProcessError(TLF("Unsupported condition '%'", condition));
1256 }
1257 } else if (tokens.size() == 3) {
1258 // infix expression
1259 const double a = evalAtomicExpression(tokens[0]);
1260 const double b = evalAtomicExpression(tokens[2]);
1261 const std::string& o = tokens[1];
1262 //std::cout << SIMTIME << " o=" << o << " a=" << a << " b=" << b << "\n";
1263 try {
1264 return evalTernaryExpression(a, o, b, condition);
1265 } catch (ProcessError& e) {
1266 throw ProcessError(TLF("Error when evaluating expression '%':\n %", condition, e.what()));
1267 }
1268 } else {
1269 const int iEnd = (int)tokens.size() - 1;
1270 for (const std::string& o : OPERATOR_PRECEDENCE) {
1271 for (int i = 1; i < iEnd; i++) {
1272 if (tokens[i] == o) {
1273 try {
1274 const double val = evalTernaryExpression(
1275 evalAtomicExpression(tokens[i - 1]), o,
1276 evalAtomicExpression(tokens[i + 1]), condition);
1277 std::vector<std::string> newTokens(tokens.begin(), tokens.begin() + (i - 1));
1278 newTokens.push_back(toString(val));
1279 newTokens.insert(newTokens.end(), tokens.begin() + (i + 2), tokens.end());
1280 return evalExpression(toString(newTokens));
1281 } catch (ProcessError& e) {
1282 throw ProcessError(TLF("Error when evaluating expression '%':\n %", condition, e.what()));
1283 }
1284 }
1285 }
1286 }
1287 throw ProcessError(TLF("Parsing expressions with % elements ('%') is not supported", toString(tokens.size()), condition));
1288 }
1289 return true;
1290}
1291
1292double
1293MSActuatedTrafficLightLogic::evalTernaryExpression(double a, const std::string& o, double b, const std::string& condition) const {
1294 if (o == "=" || 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 == ">=") {
1303 return (double)(a >= b);
1304 } else if (o == "!=") {
1305 return (double)(a != b);
1306 } else if (o == "or" || o == "||") {
1307 return (double)(a || b);
1308 } else if (o == "and" || o == "&&") {
1309 return (double)(a && b);
1310 } else if (o == "+") {
1311 return a + b;
1312 } else if (o == "-") {
1313 return a - b;
1314 } else if (o == "*") {
1315 return a * b;
1316 } else if (o == "/") {
1317 if (b == 0) {
1318 WRITE_ERRORF(TL("Division by 0 in condition '%'"), condition);
1319 return 0;
1320 }
1321 return a / b;
1322 } else if (o == "%") {
1323 return fmod(a, b);
1324 } else if (o == "**" || o == "^") {
1325 return pow(a, b);
1326 } else {
1327 throw ProcessError(TLF("Unsupported operator '%' in condition '%'", o, condition));
1328 }
1329}
1330
1331double
1332MSActuatedTrafficLightLogic::evalCustomFunction(const std::string& fun, const std::string& arg) const {
1333 std::vector<std::string> args = StringTokenizer(arg, ",").getVector();
1334 const Function& f = myFunctions.find(fun)->second;
1335 if ((int)args.size() != f.nArgs) {
1336 throw ProcessError(TLF("Function '%' requires % arguments but % were given", fun, toString(f.nArgs), toString(args.size())));
1337 }
1338 std::vector<double> args2;
1339 for (auto a : args) {
1340 args2.push_back(evalExpression(a));
1341 }
1342 myStack.push_back(myStack.back());
1343 myStack.back()["$0"] = 0;
1344 for (int i = 0; i < (int)args2.size(); i++) {
1345 myStack.back()["$" + toString(i + 1)] = args2[i];
1346 }
1347 try {
1348 ConditionMap empty;
1350 } catch (ProcessError& e) {
1351 throw ProcessError(TLF("Error when evaluating function '%' with args '%' (%)", fun, joinToString(args2, ","), e.what()));
1352 }
1353 double result = myStack.back()["$0"];
1354 myStack.pop_back();
1355 return result;
1356}
1357
1358
1359void
1360MSActuatedTrafficLightLogic::executeAssignments(const AssignmentMap& assignments, ConditionMap& conditions, const ConditionMap& forbidden) const {
1361 for (const auto& assignment : assignments) {
1362 if (evalExpression(std::get<1>(assignment))) {
1363 const std::string& id = std::get<0>(assignment);
1364 const double val = evalExpression(std::get<2>(assignment));
1365 ConditionMap::iterator it = conditions.find(id);
1366 if (it != conditions.end()) {
1367 it->second = toString(val);
1368 } else if (forbidden.find(id) != forbidden.end()) {
1369 throw ProcessError(TLF("Modifying global condition '%' is forbidden", id));
1370 } else {
1371 myStack.back()[id] = val;
1372 }
1373 }
1374 }
1375}
1376
1377
1378double
1380 if (expr.size() == 0) {
1381 throw ProcessError(TL("Invalid empty expression"));
1382 } else if (expr[0] == '!') {
1383 return evalAtomicExpression(expr.substr(1)) == 0. ? 1. : 0.;
1384 } else if (expr[0] == '-') {
1385 return -evalAtomicExpression(expr.substr(1));
1386 } else {
1387 // check for 'operator:'
1388 const size_t pos = expr.find(':');
1389 if (pos == std::string::npos) {
1390 auto it = myConditions.find(expr);
1391 if (it != myConditions.end()) {
1392 // symbol lookup
1393 return evalExpression(it->second);
1394 } else {
1395 // look at stack
1396 auto it2 = myStack.back().find(expr);
1397 if (it2 != myStack.back().end()) {
1398 return it2->second;
1399 }
1400 // must be a number
1401 return StringUtils::toDouble(expr);
1402 }
1403 } else {
1404 const std::string fun = expr.substr(0, pos);
1405 const std::string arg = expr.substr(pos + 1);
1406 if (fun == "z") {
1407 return retrieveDetExpression<MSInductLoop, SUMO_TAG_INDUCTION_LOOP>(arg, expr, true)->getTimeSinceLastDetection();
1408 } else if (fun == "a") {
1409 try {
1410 return retrieveDetExpression<MSInductLoop, SUMO_TAG_INDUCTION_LOOP>(arg, expr, true)->getTimeSinceLastDetection() == 0;
1411 } catch (ProcessError&) {
1412 return retrieveDetExpression<MSE2Collector, SUMO_TAG_LANE_AREA_DETECTOR>(arg, expr, true)->getCurrentVehicleNumber();
1413 }
1414 } else if (fun == "w") {
1415 try {
1416 return retrieveDetExpression<MSInductLoop, SUMO_TAG_INDUCTION_LOOP>(arg, expr, true)->getOccupancyTime();
1417 } catch (ProcessError&) {
1418 return retrieveDetExpression<MSE2Collector, SUMO_TAG_LANE_AREA_DETECTOR>(arg, expr, true)->getCurrentJamDuration();
1419 }
1420 } else if (fun == "g" || fun == "r") {
1421 try {
1422 int linkIndex = StringUtils::toInt(arg);
1423 if (linkIndex >= 0 && linkIndex < myNumLinks) {
1424 const std::vector<SUMOTime>& times = fun == "g" ? myLinkGreenTimes : myLinkRedTimes;
1425 if (times.empty()) {
1426 return 0;
1427 }
1429 // times are only updated at the start of a phase where
1430 // switching is possible (i.e. not during minDur).
1431 // If somebody is looking at those values in the tracker
1432 // this would be confusing
1433 const LinkState ls = getCurrentPhaseDef().getSignalState(linkIndex);
1434 if ((fun == "g" && (ls == LINKSTATE_TL_GREEN_MAJOR || ls == LINKSTATE_TL_GREEN_MINOR))
1435 || (fun == "r" && (ls == LINKSTATE_TL_RED || ls == LINKSTATE_TL_REDYELLOW))) {
1436 const SUMOTime currentGreen = SIMSTEP - myLastTrySwitchTime;
1437 return STEPS2TIME(times[linkIndex] + currentGreen);
1438 } else {
1439 return 0;
1440 }
1441 } else {
1442 return STEPS2TIME(times[linkIndex]);
1443 }
1444 }
1445 } catch (NumberFormatException&) { }
1446 throw ProcessError(TLF("Invalid link index '%' in expression '%'", arg, expr));
1447 } else if (fun == "p") {
1448 try {
1449 int linkIndex = StringUtils::toInt(arg);
1450 if (linkIndex >= 0 && linkIndex < myNumLinks) {
1451 double approachingPersons = 0;
1452 for (const MSLink* link : getLinksAt(linkIndex)) {
1453 auto* aPersons = link->getApproachingPersons();
1454 if (aPersons != nullptr) {
1455 approachingPersons += (double)aPersons->size();
1456 }
1457 }
1458 return approachingPersons;
1459 }
1460 } catch (NumberFormatException&) { }
1461 throw ProcessError(TLF("Invalid link index '%' in expression '%'", arg, expr));
1462 } else if (fun == "c") {
1463 return STEPS2TIME(getTimeInCycle());
1464 } else {
1465 if (myFunctions.find(fun) == myFunctions.end()) {
1466 throw ProcessError(TLF("Unsupported function '%' in expression '%'", fun, expr));
1467 }
1468 return evalCustomFunction(fun, arg);
1469 }
1470 }
1471 }
1472}
1473
1474
1475std::map<std::string, double>
1477 std::map<std::string, double> result;
1478 for (auto li : myInductLoops) {
1479 result[li.loop->getID()] = li.loop->getOccupancy() > 0 ? 1 : 0;
1480 }
1481 for (auto loop : myExtraLoops) {
1482 result[loop->getID()] = loop->getOccupancy() > 0 ? 1 : 0;
1483 }
1484 for (auto loop : myExtraE2) {
1485 result[loop->getID()] = loop->getCurrentVehicleNumber();
1486 }
1487 return result;
1488}
1489
1490double
1491MSActuatedTrafficLightLogic::getDetectorState(const std::string laneID) const {
1492 double result = 0.0;
1493 for (auto li : myInductLoops) {
1494 if (li.lane->getID() == laneID) {
1495 result = li.loop->getOccupancy() > 0 ? 1 : 0;
1496 break;
1497 }
1498 }
1499 return result;
1500}
1501
1502std::map<std::string, double>
1504 std::map<std::string, double> result;
1505 for (auto item : myConditions) {
1506 if (myListedConditions.count(item.first) != 0) {
1507 try {
1508 result[item.first] = evalExpression(item.second);
1509 } catch (ProcessError& e) {
1510 WRITE_ERRORF(TL("Error when retrieving conditions '%' for tlLogic '%' (%)"), item.first, getID(), e.what());
1511 }
1512 }
1513 }
1514 return result;
1515}
1516
1517const std::string
1518MSActuatedTrafficLightLogic::getParameter(const std::string& key, const std::string defaultValue) const {
1519 if (StringUtils::startsWith(key, "condition.")) {
1520 const std::string cond = key.substr(10);
1521 auto it = myConditions.find(cond);
1522 if (it != myConditions.end()) {
1523 return toString(evalExpression(it->second));
1524 } else {
1525 throw InvalidArgument(TLF("Unknown condition '%' for actuated traffic light '%'", cond, getID()));
1526 }
1527 } else {
1528 return MSSimpleTrafficLightLogic::getParameter(key, defaultValue);
1529 }
1530}
1531
1532void
1533MSActuatedTrafficLightLogic::setParameter(const std::string& key, const std::string& value) {
1534 // some pre-defined parameters can be updated at runtime
1535 if (key == "detector-gap" || key == "passing-time" || key == "file" || key == "freq" || key == "vTypes"
1536 || key == "build-all-detectors"
1537 || StringUtils::startsWith(key, "linkMaxDur")
1538 || StringUtils::startsWith(key, "linkMinDur")) {
1539 throw InvalidArgument(key + " cannot be changed dynamically for actuated traffic light '" + getID() + "'");
1540 } else if (key == "max-gap") {
1542 // overwrite custom values
1543 for (InductLoopInfo& loopInfo : myInductLoops) {
1544 loopInfo.maxGap = myMaxGap;
1545 }
1546 Parameterised::setParameter(key, value);
1547 } else if (StringUtils::startsWith(key, "max-gap:")) {
1548 const std::string laneID = key.substr(8);
1549 for (InductLoopInfo& loopInfo : myInductLoops) {
1550 if (loopInfo.lane->getID() == laneID) {
1551 loopInfo.maxGap = StringUtils::toDouble(value);
1552 Parameterised::setParameter(key, value);
1553 return;
1554 }
1555 }
1556 throw InvalidArgument(TLF("Invalid lane '%' in key '%' for actuated traffic light '%'", laneID, key, getID()));
1557 } else if (key == "jam-threshold") {
1559 // overwrite custom values
1560 for (InductLoopInfo& loopInfo : myInductLoops) {
1561 loopInfo.jamThreshold = myJamThreshold;
1562 }
1563 Parameterised::setParameter(key, value);
1564 } else if (StringUtils::startsWith(key, "jam-threshold:")) {
1565 const std::string laneID = key.substr(14);
1566 for (InductLoopInfo& loopInfo : myInductLoops) {
1567 if (loopInfo.lane->getID() == laneID) {
1568 loopInfo.jamThreshold = StringUtils::toDouble(value);
1569 Parameterised::setParameter(key, value);
1570 return;
1571 }
1572 }
1573 throw InvalidArgument(TLF("Invalid lane '%' in key '%' for actuated traffic light '%'", laneID, key, getID()));
1574 } else if (key == "show-detectors") {
1576 Parameterised::setParameter(key, value);
1577 for (InductLoopInfo& loopInfo : myInductLoops) {
1578 loopInfo.loop->setVisible(myShowDetectors);
1579 }
1580 } else if (key == "inactive-threshold") {
1582 Parameterised::setParameter(key, value);
1583 } else {
1585 }
1586}
1587
1588
1589/****************************************************************************/
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_INDUCTION_LOOP
alternative tag for e1 detector
LinkState
The right-of-way state of a link between two lanes used when constructing a NBTrafficLightLogic,...
@ LINKSTATE_TL_REDYELLOW
The link has red light (must brake) but indicates upcoming green.
@ LINKSTATE_TL_GREEN_MAJOR
The link has green light, may pass.
@ LINKSTATE_TL_RED
The link has red light (must brake)
@ LINKSTATE_TL_GREEN_MINOR
The link has green light, has to brake.
T MIN3(T a, T b, T c)
Definition StdDefs.h:93
T MIN2(T a, T b)
Definition StdDefs.h:80
T MAX2(T a, T b)
Definition StdDefs.h:86
T MAX3(T a, T b, T c)
Definition StdDefs.h:100
std::string joinNamedToString(const std::set< T *, C > &ns, const T_BETWEEN &between)
Definition ToString.h:332
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition ToString.h:289
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 accessible from the current working directory.
double myDetectorGap
The detector distance in seconds.
void findTargets(int origStep, int n, SUMOTime priorTransition, std::map< int, SUMOTime > &found)
FunctionMap myFunctions
The loaded functions.
double myJamThreshold
The minimum continuous occupancy time to mark a detector as jammed.
bool myBuildAllDetectors
Whether all detectors shall be built.
double myMaxGap
The maximum gap to check in seconds.
const std::string getParameter(const std::string &key, const std::string defaultValue="") const override
try to get the value of the given parameter (including prefixed parameters)
std::map< int, std::map< int, std::vector< int > > > myTargets
std::vector< SwitchingRules > mySwitchingRules
std::vector< std::map< std::string, double > > myStack
The function call stack;.
double evalAtomicExpression(const std::string &expr) const
evaluate atomic expression
SUMOTime trySwitch() override
Switches to the next phase.
std::set< int > getMultiNextTargets() const
find green phases target by a next attribute
SUMOTime myLastTrySwitchTime
last time trySwitch was called
int getDetectorPriority(const InductLoopInfo &loopInfo) const
SUMOTime myFreq
The frequency for aggregating detector output.
std::vector< const MSInductLoop * > myExtraLoops
extra loops for output/tracking
bool myShowDetectors
Whether the detectors shall be shown in the GUI.
std::vector< SUMOTime > myLinkMaxGreenTimes
maximum consecutive time that the given link may remain green
MSActuatedTrafficLightLogic(MSTLLogicControl &tlcontrol, const std::string &id, const std::string &programID, const SUMOTime offset, const MSSimpleTrafficLightLogic::Phases &phases, int step, SUMOTime delay, const Parameterised::Map &parameter, const std::string &basePath, const ConditionMap &conditions=ConditionMap(), const AssignmentMap &assignments=AssignmentMap(), const FunctionMap &functions=FunctionMap())
Constructor.
SUMOTime getMaxDur(int step=-1) const override
std::vector< std::vector< const MSLink * > > myCrossingsForPhase
AssignmentMap myAssignments
The condition assignments.
std::string myVehicleTypes
Whether detector output separates by vType.
void loadState(MSTLLogicControl &tlcontrol, SUMOTime t, int step, SUMOTime spentDuration, bool active) override
restores the tls state
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:1186
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:961
double getLength() const
Returns the lane's length.
Definition MSLane.h:612
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition MSLane.cpp:3230
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition MSLane.h:730
MSDetectorControl & getDetectorControl()
Returns the detector control.
Definition MSNet.h:455
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition MSNet.cpp:187
MSEventControl * getBeginOfTimestepEvents()
Returns the event control for events executed at the begin of a time step.
Definition MSNet.h:485
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.
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 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)
Creates an instance of an e1 detector using the given values.
const std::string & getID() const
Returns the id.
Definition Named.h:74
T get(const std::string &id) const
Retrieves an item.
static OptionsCont & getOptions()
Retrieves the options.
bool hasParameter(const std::string &key) const
Returns whether the parameter is set.
std::map< std::string, std::string > Map
parameters map
double getDouble(const std::string &key, const double defaultValue) const
Returns the value for a given key converted to a double.
const Parameterised::Map & getParametersMap() const
Returns the inner key/value map.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
static const RGBColor ORANGE
Definition RGBColor.h:194
static const RGBColor GREEN
Definition RGBColor.h:189
static const RGBColor RED
named colors
Definition RGBColor.h:188
std::vector< std::string > getVector()
return vector of strings
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
static bool toBool(const std::string &sData)
converts a string into the bool value described by it by calling the char-type converter
#define DEBUG_COND