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