Eclipse SUMO - Simulation of Urban MObility
MSActuatedTrafficLightLogic.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2022 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>
31 #include <microsim/MSGlobals.h>
32 #include <microsim/MSNet.h>
33 #include "MSTrafficLightLogic.h"
35 #include <microsim/MSLane.h>
36 #include <microsim/MSEdge.h>
40 
41 //#define DEBUG_DETECTORS
42 //#define DEBUG_PHASE_SELECTION
43 #define DEBUG_COND (getID()=="C")
44 
45 // ===========================================================================
46 // static members
47 // ===========================================================================
48 const std::vector<std::string> MSActuatedTrafficLightLogic::OPERATOR_PRECEDENCE({
49  "**", "^", "*", "/", "+", "-", "%",
50  "=", "==", "!=", "<", ">", "<=", ">=",
51  "and", "&&", "or", "||",
52 });
53 
54 // ===========================================================================
55 // parameter defaults definitions
56 // ===========================================================================
57 #define DEFAULT_MAX_GAP "3.0"
58 #define DEFAULT_PASSING_TIME "1.9"
59 #define DEFAULT_DETECTOR_GAP "2.0"
60 #define DEFAULT_INACTIVE_THRESHOLD "180"
61 #define DEFAULT_CURRENT_PRIORITY 10
62 
63 #define DEFAULT_LENGTH_WITH_GAP 7.5
64 
65 #define NO_DETECTOR "NO_DETECTOR"
66 
67 // ===========================================================================
68 // method definitions
69 // ===========================================================================
71  const std::string& id, const std::string& programID,
72  const SUMOTime offset,
73  const Phases& phases,
74  int step, SUMOTime delay,
75  const std::map<std::string, std::string>& parameter,
76  const std::string& basePath,
77  const std::map<std::string, std::string>& conditions) :
78  MSSimpleTrafficLightLogic(tlcontrol, id, programID, offset, TrafficLightType::ACTUATED, phases, step, delay, parameter),
79  myLastTrySwitchTime(0),
80  myConditions(conditions),
81  myTraCISwitch(false),
82  myDetectorPrefix(id + "_" + programID + "_") {
87  myShowDetectors = StringUtils::toBool(getParameter("show-detectors", toString(OptionsCont::getOptions().getBool("tls.actuated.show-detectors"))));
88  myFile = FileHelpers::checkForRelativity(getParameter("file", "NUL"), basePath);
90  myVehicleTypes = getParameter("vTypes", "");
91 }
92 
93 
95 
96 void
99  if (myLanes.size() == 0) {
100  // must be an older network
101  WRITE_WARNING("Traffic light '" + getID() + "' does not control any links");
102  }
103  bool warn = true; // warn only once
104  const int numLinks = (int)myLinks.size();
105 
106  // Detector position should be computed based on road speed. If the position
107  // is quite far away and the minDur is short this may cause the following
108  // problems:
109  //
110  // 1) high flow failure:
111  // In a standing queue, no vehicle touches the detector.
112  // By the time the queue advances, the detector gap has been exceeded and the phase terminates prematurely
113  //
114  // 2) low flow failure
115  // The standing queue is fully between stop line and detector and there are no further vehicles.
116  // The minDur is too short to let all vehicles pass
117  //
118  // Problem 2) is not so critical because there is less potential for
119  // jamming in a low-flow situation. In contrast, problem 1) should be
120  // avoided as it has big jamming potential. We compute an upper bound for the
121  // detector distance to avoid it
122 
123 
124  // change values for setting the loops and lanestate-detectors, here
125  //SUMOTime inductLoopInterval = 1; //
126  // build the induct loops
127  std::map<const MSLane*, MSInductLoop*> laneInductLoopMap;
128  std::map<MSInductLoop*, const MSLane*> inductLoopLaneMap; // in case loops are placed further upstream
129  int detEdgeIndex = -1;
130  int detLaneIndex = 0;
131  MSEdge* prevDetEdge = nullptr;
132  for (LaneVector& lanes : myLanes) {
133  for (MSLane* lane : lanes) {
134  if (noVehicles(lane->getPermissions())) {
135  // do not build detectors on green verges or sidewalks
136  continue;
137  }
138  if (laneInductLoopMap.find(lane) != laneInductLoopMap.end()) {
139  // only build one detector per lane
140  continue;
141  }
142  const SUMOTime minDur = getMinimumMinDuration(lane);
143  if (minDur == std::numeric_limits<SUMOTime>::max()) {
144  // only build detector if this lane is relevant for an actuated phase
145  continue;
146  }
147  const std::string customID = getParameter(lane->getID());
148  double length = lane->getLength();
149  double ilpos;
150  double inductLoopPosition;
151  MSInductLoop* loop = nullptr;
152  if (&lane->getEdge() != prevDetEdge) {
153  detEdgeIndex++;
154  detLaneIndex = 0;
155  prevDetEdge = &lane->getEdge();
156  } else {
157  detLaneIndex++;
158  }
159  if (customID == "") {
160  double speed = lane->getSpeedLimit();
161  inductLoopPosition = MIN2(
162  myDetectorGap * speed,
163  (STEPS2TIME(minDur) / myPassingTime + 0.5) * DEFAULT_LENGTH_WITH_GAP);
164 
165  // check whether the lane is long enough
166  ilpos = length - inductLoopPosition;
167  MSLane* placementLane = lane;
168  while (ilpos < 0 && placementLane->getIncomingLanes().size() == 1) {
169  placementLane = placementLane->getLogicalPredecessorLane();
170  ilpos += placementLane->getLength();
171  }
172  if (ilpos < 0) {
173  ilpos = 0;
174  }
175  // Build the induct loop and set it into the container
176  std::string id = myDetectorPrefix + "D" + toString(detEdgeIndex) + "." + toString(detLaneIndex);
177  loop = static_cast<MSInductLoop*>(nb.createInductLoop(id, placementLane, ilpos, myVehicleTypes, (int)PersonMode::NONE, myShowDetectors));
179  } else if (customID == NO_DETECTOR) {
180  continue;
181  } else {
183  if (loop == nullptr) {
184  WRITE_ERROR("Unknown inductionLoop '" + customID + "' given as custom detector for actuated tlLogic '" + getID() + "', program '" + getProgramID() + ".");
185  continue;
186  }
187  ilpos = loop->getPosition();
188  inductLoopPosition = length - ilpos;
189  }
190  laneInductLoopMap[lane] = loop;
191  inductLoopLaneMap[loop] = lane;
192  const double maxGap = getDouble("max-gap:" + lane->getID(), myMaxGap);
193  myInductLoops.push_back(InductLoopInfo(loop, (int)myPhases.size(), maxGap));
194 
195  if (warn && floor(floor(inductLoopPosition / DEFAULT_LENGTH_WITH_GAP) * myPassingTime) > STEPS2TIME(minDur)) {
196  // warn if the minGap is insufficient to clear vehicles between stop line and detector
197  WRITE_WARNING("At actuated tlLogic '" + getID() + "', minDur " + time2string(minDur) + " is too short for a detector gap of " + toString(inductLoopPosition) + "m.");
198  warn = false;
199  }
200  }
201  }
202  // assign loops to phase index (myInductLoopsForPhase)
203  // 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
204  // greenMinor is ambiguous as vehicles may not be able to drive
205  // Under the following condition we allow actuation from minor link:
206  // check1a : the minor link is minor in all phases
207  // check1b : there is another major link from the same lane in the current phase
208  // (Under these conditions we assume that the minor link is unimportant and traffic is mostly for the major link)
209  //
210  // check1c: when the lane has only one edge, we treat greenMinor as green as there would be no actuation otherwise
211  // check1d: for turnarounds 1b is sufficient and we do not require 1a
212  //
213  // 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
214 
215  // also assign loops to link index for validation:
216  // check if all links from actuated phases (minDur != maxDur) have an inductionloop in at least one phase
217  const SVCPermissions motorized = ~(SVC_PEDESTRIAN | SVC_BICYCLE);
218  std::map<int, std::set<MSInductLoop*> > linkToLoops;
219  std::set<int> actuatedLinks;
220 
221  std::vector<bool> neverMajor(numLinks, true);
222  for (const MSPhaseDefinition* phase : myPhases) {
223  const std::string& state = phase->getState();
224  for (int i = 0; i < numLinks; i++) {
225  if (state[i] == LINKSTATE_TL_GREEN_MAJOR) {
226  neverMajor[i] = false;
227  }
228  }
229  }
230  std::vector<bool> oneLane(numLinks, false);
231  std::vector<bool> turnaround(numLinks, true);
232  for (int i = 0; i < numLinks; i++) {
233  for (MSLane* lane : getLanesAt(i)) {
234  // only count motorized vehicle lanes
235  int numMotorized = 0;
236  for (MSLane* l : lane->getEdge().getLanes()) {
237  if ((l->getPermissions() & motorized) != 0) {
238  numMotorized++;
239  }
240  }
241  if (numMotorized == 1) {
242  oneLane[i] = true;
243  break;
244  }
245  }
246  for (MSLink* link : getLinksAt(i)) {
247  if (!link->isTurnaround()) {
248  turnaround[i] = false;
249  break;
250  }
251  }
252  }
253 
254 
255  for (const MSPhaseDefinition* phase : myPhases) {
256  const int phaseIndex = (int)myInductLoopsForPhase.size();
257  std::set<MSInductLoop*> loops;
258  if (phase->isActuted()) {
259  const std::string& state = phase->getState();
260  // collect indices of all green links for the phase
261  std::set<int> greenLinks;
262  // collect green links for each induction loops (in this phase)
263  std::map<MSInductLoop*, std::set<int> > loopLinks;
264 
265  for (int i = 0; i < numLinks; i++) {
266  if (state[i] == LINKSTATE_TL_GREEN_MAJOR
267  || (state[i] == LINKSTATE_TL_GREEN_MINOR
268  && (((neverMajor[i] || turnaround[i]) // check1a, 1d
269  && hasMajor(state, getLanesAt(i))) // check1b
270  || oneLane[i])) // check1c
271  ) {
272  greenLinks.insert(i);
273  if (state[i] == LINKSTATE_TL_GREEN_MAJOR || !turnaround[i]) {
274  actuatedLinks.insert(i);
275  }
276  }
277 #ifdef DEBUG_DETECTORS
278  if (DEBUG_COND) {
279  std::cout << " phase=" << phaseIndex << " i=" << i << " state=" << state[i] << " green=" << greenLinks.count(i) << " oneLane=" << oneLane[i]
280  << " turn=" << turnaround[i] << " loopLanes=";
281  for (MSLane* lane : getLanesAt(i)) {
282  if (laneInductLoopMap.count(lane) != 0) {
283  std::cout << lane->getID() << " ";
284  }
285  }
286  std::cout << "\n";
287  }
288 #endif
289  for (MSLane* lane : getLanesAt(i)) {
290  if (laneInductLoopMap.count(lane) != 0) {
291  loopLinks[laneInductLoopMap[lane]].insert(i);
292  }
293  }
294  }
295  for (auto& item : loopLinks) {
296  MSInductLoop* loop = item.first;
297  const MSLane* loopLane = inductLoopLaneMap[loop];
298  bool usable = true;
299  // check1
300  for (int j : item.second) {
301  if (greenLinks.count(j) == 0) {
302  usable = false;
303 #ifdef DEBUG_DETECTORS
304  if (DEBUG_COND) {
305  std::cout << " phase=" << phaseIndex << " check1: loopLane=" << loopLane->getID() << " notGreen=" << j << " oneLane[j]=" << oneLane[j] << "\n";
306  }
307 #endif
308  break;
309  }
310  }
311  // check2
312  if (usable) {
313  for (MSLink* link : loopLane->getLinkCont()) {
314  if (link->isTurnaround()) {
315  continue;
316  }
317  const MSLane* next = link->getLane();
318  if (laneInductLoopMap.count(next) != 0) {
319  MSInductLoop* nextLoop = laneInductLoopMap[next];
320  for (int j : loopLinks[nextLoop]) {
321  if (greenLinks.count(j) == 0) {
322  usable = false;
323 #ifdef DEBUG_DETECTORS
324  if (DEBUG_COND) std::cout << " phase=" << phaseIndex << " check2: loopLane=" << loopLane->getID()
325  << " nextLane=" << next->getID() << " nextLink=" << j << " nextState=" << state[j] << "\n";
326 #endif
327  break;
328  }
329  }
330  }
331  }
332  }
333 
334  if (usable) {
335  loops.insert(item.first);
336 #ifdef DEBUG_DETECTORS
337  if (DEBUG_COND) {
338  std::cout << " phase=" << phaseIndex << " usableLoops=" << item.first->getID() << " links=" << joinToString(item.second, " ") << "\n";
339  }
340 #endif
341  for (int j : item.second) {
342  linkToLoops[j].insert(item.first);
343  }
344  }
345  }
346  if (loops.size() == 0) {
347  WRITE_WARNINGF("At actuated tlLogic '%', actuated phase % has no controlling detector.", getID(), toString(phaseIndex));
348  }
349  }
350 #ifdef DEBUG_DETECTORS
351  if (DEBUG_COND) {
352  std::cout << " phase=" << phaseIndex << " loops=" << joinNamedToString(loops, " ") << "\n";
353  }
354  if (DEBUG_COND) {
355  std::cout << " linkToLoops:\n";
356  for (auto item : linkToLoops) {
357  std::cout << " link=" << item.first << " loops=" << joinNamedToString(item.second, " ") << "\n";
358  }
359  }
360 #endif
361  std::vector<InductLoopInfo*> loopInfos;
362  myInductLoopsForPhase.push_back(loopInfos);
363  for (MSInductLoop* loop : loops) {
364  for (InductLoopInfo& loopInfo : myInductLoops) {
365  if (loopInfo.loop == loop) {
366  myInductLoopsForPhase.back().push_back(&loopInfo);
367  loopInfo.servedPhase[phaseIndex] = true;
368  }
369  }
370  }
371  }
372 #ifdef DEBUG_DETECTORS
373  if (DEBUG_COND) {
374  std::cout << "final linkToLoops:\n";
375  for (auto item : linkToLoops) {
376  std::cout << " link=" << item.first << " loops=" << joinNamedToString(item.second, " ") << "\n";
377  }
378  }
379 #endif
380  for (int i : actuatedLinks) {
381  if (linkToLoops[i].size() == 0 && myLinks[i].size() > 0
382  && (myLinks[i].front()->getLaneBefore()->getPermissions() & motorized) != 0) {
383  if (getParameter(myLinks[i].front()->getLaneBefore()->getID()) != NO_DETECTOR) {
384  WRITE_WARNINGF("At actuated tlLogic '%', linkIndex % has no controlling detector.", getID(), toString(i));
385  }
386  }
387  }
388  // parse maximum green times for each link (optional)
389  for (const auto& kv : getParametersMap()) {
390  if (StringUtils::startsWith(kv.first, "linkMaxDur:")) {
391  int link = StringUtils::toInt(kv.first.substr(11));
392  if (link < 0 || link >= myNumLinks) {
393  WRITE_ERROR("Invalid link '" + kv.first.substr(11) + "' given as linkMaxDur parameter for actuated tlLogic '" + getID() + "', program '" + getProgramID() + ".");
394  continue;
395  }
396  if (myLinkMaxGreenTimes.empty()) {
397  myLinkMaxGreenTimes = std::vector<SUMOTime>(myNumLinks, std::numeric_limits<SUMOTime>::max());
398  }
399  myLinkMaxGreenTimes[link] = string2time(kv.second);
400  } else if (StringUtils::startsWith(kv.first, "linkMinDur:")) {
401  int link = StringUtils::toInt(kv.first.substr(11));
402  if (link < 0 || link >= myNumLinks) {
403  WRITE_ERROR("Invalid link '" + kv.first.substr(11) + "' given as linkMinDur parameter for actuated tlLogic '" + getID() + "', program '" + getProgramID() + ".");
404  continue;
405  }
406  if (myLinkMinGreenTimes.empty()) {
407  myLinkMinGreenTimes = std::vector<SUMOTime>(myNumLinks, 0);
408  }
409  myLinkMinGreenTimes[link] = string2time(kv.second);
410  }
411  }
413  if (myLinkMaxGreenTimes.size() > 0 || myLinkMinGreenTimes.size() > 0 || mySwitchingRules.size() > 0) {
414  myLinkGreenTimes = std::vector<SUMOTime>(myNumLinks, 0);
415  myLinkRedTimes = std::vector<SUMOTime>(myNumLinks, 0);
416  }
417  //std::cout << SIMTIME << " linkMaxGreenTimes=" << toString(myLinkMaxGreenTimes) << "\n";
418 }
419 
420 
421 void
423  for (int i = 0; i < (int)myPhases.size(); i++) {
424  SwitchingRules sr;
425  MSPhaseDefinition* phase = myPhases[i];
426  std::vector<int> nextPhases = phase->nextPhases;
427  if (nextPhases.size() == 0) {
428  nextPhases.push_back((i + 1) % (int)myPhases.size());
429  }
430  for (int next : nextPhases) {
431  if (next >= 0 && next < (int)myPhases.size()) {
432  const MSPhaseDefinition* nextPhase = myPhases[next];
433  if (nextPhase->earlyTarget != "" || nextPhase->finalTarget != "") {
434  sr.enabled = true;
435  // simplifies later code
436  phase->nextPhases = nextPhases;
437  }
438  }
439  }
440  mySwitchingRules.push_back(sr);
441  }
442 }
443 
444 
445 SUMOTime
447  SUMOTime result = std::numeric_limits<SUMOTime>::max();
448  for (const MSPhaseDefinition* phase : myPhases) {
449  const std::string& state = phase->getState();
450  for (int i = 0; i < (int)state.size(); i++) {
451  if (state[i] == LINKSTATE_TL_GREEN_MAJOR || state[i] == LINKSTATE_TL_GREEN_MINOR) {
452  for (MSLane* cand : getLanesAt(i)) {
453  if (lane == cand) {
454  if (phase->isActuted()) {
455  result = MIN2(result, phase->minDuration);
456  }
457  }
458  }
459  }
460  }
461  }
462  return result;
463 }
464 
465 bool
466 MSActuatedTrafficLightLogic::hasMajor(const std::string& state, const LaneVector& lanes) const {
467  for (int i = 0; i < (int)state.size(); i++) {
468  if (state[i] == LINKSTATE_TL_GREEN_MAJOR) {
469  for (MSLane* cand : getLanesAt(i)) {
470  for (MSLane* lane : lanes) {
471  if (lane == cand) {
472  return true;
473  }
474  }
475  }
476  }
477  }
478  return false;
479 }
480 
481 
482 // ------------ Switching and setting current rows
483 void
486  for (InductLoopInfo& loopInfo : myInductLoops) {
487  loopInfo.loop->setVisible(myShowDetectors);
488  }
489 }
490 
491 
492 void
495  for (InductLoopInfo& loopInfo : myInductLoops) {
496  loopInfo.loop->setVisible(false);
497  }
498 }
499 
500 void
502  SUMOTime simStep, int step, SUMOTime stepDuration) {
503  // do not change timing if the phase changes
504  if (step >= 0 && step != myStep) {
505  myStep = step;
507  setTrafficLightSignals(simStep);
508  tlcontrol.get(getID()).executeOnSwitchActions();
509  } else if (step < 0) {
510  // TraCI requested new timing
512  mySwitchCommand = new SwitchCommand(tlcontrol, this, stepDuration + simStep);
514  mySwitchCommand, stepDuration + simStep);
515  myTraCISwitch = true;
516  }
517 }
518 
519 SUMOTime
521  // checks if the actual phase should be continued
522  // @note any vehicles which arrived during the previous phases which are now waiting between the detector and the stop line are not
523  // considere here. RiLSA recommends to set minDuration in a way that lets all vehicles pass the detector
525  if (myLinkGreenTimes.size() > 0) {
526  // constraints exist, record green time durations for each link
527  const std::string& state = getCurrentPhaseDef().getState();
528  SUMOTime lastDuration = SIMSTEP - myLastTrySwitchTime;
529  for (int i = 0; i < myNumLinks; i++) {
530  if (state[i] == 'G' || state[i] == 'g') {
531  myLinkGreenTimes[i] += lastDuration;
532  } else {
533  myLinkGreenTimes[i] = 0;
534  }
535  if (state[i] == 'r' || state[i] == 'u') {
536  myLinkRedTimes[i] += lastDuration;
537  } else {
538  myLinkRedTimes[i] = 0;
539  }
540  }
541  }
542  myLastTrySwitchTime = now;
543  // decide the next phase
544  const bool multiTarget = myPhases[myStep]->nextPhases.size() > 1 && myPhases[myStep]->nextPhases.front() >= 0;
545  const int origStep = myStep;
546  int nextStep = myStep;
547  SUMOTime actDuration = now - myPhases[myStep]->myLastSwitch;
548 
549  if (mySwitchingRules[myStep].enabled) {
550  const bool mustSwitch = MIN2(getCurrentPhaseDef().maxDuration - actDuration, getLatest()) <= 0;
551  nextStep = decideNextPhaseCustom(mustSwitch);
552  } else {
553  // default algorithm
554  const double detectionGap = gapControl();
555 #ifdef DEBUG_PHASE_SELECTION
556  if (DEBUG_COND) {
557  std::cout << SIMTIME << " p=" << myStep << " trySwitch dGap=" << detectionGap << " multi=" << multiTarget << "\n";
558  }
559 #endif
560  if (detectionGap < std::numeric_limits<double>::max() && !multiTarget && !myTraCISwitch) {
561  return duration(detectionGap);
562  }
563  if (multiTarget) {
564  nextStep = decideNextPhase();
565  } else {
566  if (myPhases[myStep]->nextPhases.size() == 1 && myPhases[myStep]->nextPhases.front() >= 0) {
567  nextStep = myPhases[myStep]->nextPhases.front();
568  } else {
569  nextStep = (myStep + 1) % (int)myPhases.size();
570  }
571  }
572  }
573 
574  myTraCISwitch = false;
575  SUMOTime linkMinDur = getLinkMinDuration(getTarget(nextStep));
576  if (linkMinDur > 0) {
577  // for multiTarget, the current phase must be extended but if another
578  // targer is chosen, earlier switching than linkMinDur is possible
579  return multiTarget ? TIME2STEPS(1) : linkMinDur;
580  }
581  myStep = nextStep;
582  assert(myStep <= (int)myPhases.size());
583  assert(myStep >= 0);
584  //stores the time the phase started
585  const SUMOTime prevStart = myPhases[myStep]->myLastSwitch;
586  if (myStep != origStep) {
587  myPhases[origStep]->myLastEnd = now;
588  myPhases[myStep]->myLastSwitch = now;
589  actDuration = 0;
590  }
591  // activate coloring
592  if ((myShowDetectors || multiTarget) && getCurrentPhaseDef().isGreenPhase()) {
593  for (InductLoopInfo* loopInfo : myInductLoopsForPhase[myStep]) {
594  //std::cout << SIMTIME << " p=" << myStep << " loopinfo=" << loopInfo->loop->getID() << " set lastGreen=" << STEPS2TIME(now) << "\n";
595  loopInfo->loop->setSpecialColor(&RGBColor::GREEN);
596  loopInfo->lastGreenTime = now;
597  }
598  }
599  // set the next event
600  return MAX3(TIME2STEPS(1), getCurrentPhaseDef().minDuration - actDuration, getEarliest(prevStart));
601 }
602 
603 
604 // ------------ "actuated" algorithm methods
605 SUMOTime
606 MSActuatedTrafficLightLogic::duration(const double detectionGap) const {
607  assert(getCurrentPhaseDef().isGreenPhase());
608  assert((int)myPhases.size() > myStep);
609  const SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
610  // ensure that minimum duration is kept
611  SUMOTime newDuration = getCurrentPhaseDef().minDuration - actDuration;
612  // try to let the last detected vehicle pass the intersection (duration must be positive)
613  newDuration = MAX3(newDuration, TIME2STEPS(myDetectorGap - detectionGap), SUMOTime(1));
614  // cut the decimal places to ensure that phases always have integer duration
615  if (newDuration % 1000 != 0) {
616  const SUMOTime totalDur = newDuration + actDuration;
617  newDuration = (totalDur / 1000 + 1) * 1000 - actDuration;
618  }
619  // ensure that the maximum duration is not exceeded
620  newDuration = MIN3(newDuration, getCurrentPhaseDef().maxDuration - actDuration, getLatest());
621  return newDuration;
622 }
623 
624 
625 double
627  //intergreen times should not be lengthend
628  assert((int)myPhases.size() > myStep);
629  double result = std::numeric_limits<double>::max();
631  return result;
632  }
633  // switch off active colors
634  if (myShowDetectors) {
635  for (InductLoopInfo& loopInfo : myInductLoops) {
636  if (loopInfo.lastGreenTime < loopInfo.loop->getLastDetectionTime()) {
637  loopInfo.loop->setSpecialColor(&RGBColor::RED);
638  } else {
639  loopInfo.loop->setSpecialColor(nullptr);
640  }
641  }
642  }
643  if (!getCurrentPhaseDef().isGreenPhase()) {
644  return result; // end current phase
645  }
646 
647  // Checks, if the maxDuration is kept. No phase should last longer than maxDuration.
648  SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
649  if (actDuration >= getCurrentPhaseDef().maxDuration || maxLinkDurationReached() || getLatest() == 0) {
650 #ifdef DEBUG_PHASE_SELECTION
651  if (DEBUG_COND) {
652  std::cout << SIMTIME << " actDuration=" << STEPS2TIME(actDuration) << " maxDur=" << STEPS2TIME(getCurrentPhaseDef().maxDuration)
653  << " maxLinkDurationReached=" << maxLinkDurationReached() << " latest=" << STEPS2TIME(getLatest()) << "\n";
654  }
655 #endif
656  return result; // end current phase
657  }
658 
659  // now the gapcontrol starts
660  for (InductLoopInfo* loopInfo : myInductLoopsForPhase[myStep]) {
661  MSInductLoop* loop = loopInfo->loop;
663  const double actualGap = loop->getTimeSinceLastDetection();
664  if (actualGap < loopInfo->maxGap) {
665  result = MIN2(result, actualGap);
666  }
667  }
668  return result;
669 }
670 
671 int
673  const auto& cands = myPhases[myStep]->nextPhases;
674  // decide by priority
675  // first target is the default when thre is no traffic
676  // @note: to keep the current phase, even when there is no traffic, it must be added to 'next' explicitly
677  int result = cands.front();
678  int maxPrio = 0;
679  SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
680  const bool canExtend = actDuration < getCurrentPhaseDef().maxDuration && !maxLinkDurationReached() && getLatest() > 0;
681  if (canExtend) {
682  // consider keeping the current phase until maxDur is reached
683  // (only when there is still traffic in that phase)
684  int currentPrio = getPhasePriority(myStep);
685 #ifdef DEBUG_PHASE_SELECTION
686  std::cout << SIMTIME << " p=" << myStep << " loops=" << myInductLoopsForPhase[myStep].size() << " currentPrio=" << currentPrio << "\n";
687 #endif
688  if (currentPrio > maxPrio) {
689  result = myStep;
690  maxPrio = currentPrio;
691  }
692  }
693  for (int step : cands) {
694  int target = getTarget(step);
695  int prio = getPhasePriority(target);
696 #ifdef DEBUG_PHASE_SELECTION
697  if (DEBUG_COND) {
698  std::cout << SIMTIME << " p=" << myStep << " step=" << step << " target=" << target << " loops=" << myInductLoopsForPhase[target].size() << " prio=" << prio << "\n";
699  }
700 #endif
701  if (prio > maxPrio && canExtendLinkGreen(target)) {
702  maxPrio = prio;
703  result = step;
704  }
705  }
706  // prevent starvation in phases that are not direct targets
707  for (const InductLoopInfo& loopInfo : myInductLoops) {
708  int prio = getDetectorPriority(loopInfo);
709  if (prio > maxPrio) {
710  result = cands.front();
711  if (result == myStep) {
712  WRITE_WARNING("At actuated tlLogic '" + getID()
713  + "', starvation at e1Detector '" + loopInfo.loop->getID()
714  + "' which cannot be reached from the default phase " + toString(myStep) + ".");
715  }
716  // use default phase to reach other phases
717 #ifdef DEBUG_PHASE_SELECTION
718  if (DEBUG_COND) {
719  std::cout << SIMTIME << " p=" << myStep << " loop=" << loopInfo.loop->getID() << " prio=" << prio << " next=" << result << "\n";
720  }
721 #endif
722  break;
723  }
724  }
725  return result;
726 }
727 
728 
729 int
731  int origStep = step;
732  // if step is a transition, find the upcoming green phase
733  while (!myPhases[step]->isGreenPhase()) {
734  if (myPhases[step]->nextPhases.size() > 0 && myPhases[step]->nextPhases.front() >= 0) {
735  if (myPhases[step]->nextPhases.size() > 1) {
736  WRITE_WARNING("At actuated tlLogic '" + getID() + "', transition phase " + toString(step) + " should not have multiple next phases");
737  }
738  step = myPhases[step]->nextPhases.front();
739  } else {
740  step = (step + 1) % (int)myPhases.size();
741  }
742  if (step == origStep) {
743  WRITE_WARNING("At actuated tlLogic '" + getID() + "', infinite transition loop from phase " + toString(origStep));
744  return 0;
745  }
746  }
747  return step;
748 }
749 
750 int
752  MSInductLoop* loop = loopInfo.loop;
753  const double actualGap = loop->getTimeSinceLastDetection();
754  if (actualGap < loopInfo.maxGap || loopInfo.lastGreenTime < loop->getLastDetectionTime()) {
755  SUMOTime inactiveTime = MSNet::getInstance()->getCurrentTimeStep() - loopInfo.lastGreenTime;
756  // @note. Inactive time could also be tracked regardless of current activity (to increase robustness in case of detection failure
757  if (inactiveTime > myInactiveThreshold) {
758 #ifdef DEBUG_PHASE_SELECTION
759  if (DEBUG_COND) {
760  std::cout << " loop=" << loop->getID() << " gap=" << loop->getTimeSinceLastDetection() << " lastGreen=" << STEPS2TIME(loopInfo.lastGreenTime)
761  << " lastDetection=" << STEPS2TIME(loop->getLastDetectionTime()) << " inactive=" << STEPS2TIME(inactiveTime) << "\n";
762  }
763 #endif
764  return (int)STEPS2TIME(inactiveTime);
765  } else {
766  // give bonus to detectors that are currently served (if that phase can stil be extended)
767  if (loopInfo.servedPhase[myStep]) {
768  SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - myPhases[myStep]->myLastSwitch;
769  const bool canExtend = actDuration < getCurrentPhaseDef().maxDuration || getLatest() > 0;
770  if (canExtend) {
772  } else {
773  return 0;
774  }
775  }
776  return 1;
777  }
778  }
779  return 0;
780 }
781 
782 int
784  int result = 0;
785  for (const InductLoopInfo* loopInfo : myInductLoopsForPhase[step]) {
786  result += getDetectorPriority(*loopInfo);
787  }
788  return result;
789 }
790 
791 
792 void
794  myShowDetectors = show;
795  for (InductLoopInfo& loopInfo : myInductLoops) {
796  loopInfo.loop->setVisible(myShowDetectors);
797  }
798 }
799 
800 
801 bool
803  if (myLinkMaxGreenTimes.empty()) {
804  return false;
805  }
806  for (int i = 0; i < myNumLinks; i++) {
807  if (myLinkGreenTimes[i] >= myLinkMaxGreenTimes[i]) {
808  //std::cout << SIMTIME << " maxLinkDurationReached i=" << i << "\n";
809  return true;
810  }
811  }
812  return false;
813 }
814 
815 bool
817  if (myLinkMaxGreenTimes.empty()) {
818  return true;
819  }
820  const std::string& targetState = myPhases[target]->getState();
821  for (int i = 0; i < myNumLinks; i++) {
822  if (myLinkGreenTimes[i] >= myLinkMaxGreenTimes[i] && (
823  targetState[i] == 'G' || targetState[i] == 'g')) {
824  //std::cout << SIMTIME << " cannotExtendLinkGreen target=" << target << " i=" << i << "\n";
825  return false;
826  }
827  }
828  return true;
829 }
830 
831 SUMOTime
833  SUMOTime result = 0;
834  if (target != myStep && myLinkMinGreenTimes.size() > 0) {
835  const std::string& state = myPhases[myStep]->getState();
836  const std::string& targetState = myPhases[target]->getState();
837  for (int i = 0; i < myNumLinks; i++) {
839  && (state[i] == 'G' || state[i] == 'g')
840  && !(targetState[i] == 'G' || targetState[i] == 'g')) {
841  result = MAX2(result, myLinkMinGreenTimes[i] - myLinkGreenTimes[i]);
842  //std::cout << SIMTIME << " getLinkMinDuration myStep=" << myStep << " target=" << target << " i=" << i
843  // << " greenTime=" << STEPS2TIME(myLinkGreenTimes[i]) << " min=" << STEPS2TIME(myLinkMinGreenTimes[i]) << " result=" << STEPS2TIME(result) << "\n";
844  }
845  }
846  }
847  return result;
848 }
849 
850 int
852  for (int next : getCurrentPhaseDef().nextPhases) {
853  const MSPhaseDefinition* phase = myPhases[next];
854  const std::string& condition = mustSwitch ? phase->finalTarget : phase->earlyTarget;
855  //std::cout << SIMTIME << " mustSwitch=" << mustSwitch << " condition=" << condition << "\n";
856  if (condition != "" && evalExpression(condition)) {
857  return next;
858  }
859  }
860  return mustSwitch ? getCurrentPhaseDef().nextPhases.back() : myStep;
861 }
862 
863 
864 double
865 MSActuatedTrafficLightLogic::evalExpression(const std::string& condition) const {
866  const size_t bracketOpen = condition.find('(');
867  if (bracketOpen != std::string::npos) {
868  // find matching closing bracket
869  size_t bracketClose = std::string::npos;
870  int open = 1;
871  for (size_t i = bracketOpen + 1; i < condition.size(); i++) {
872  if (condition[i] == '(') {
873  open++;
874  } else if (condition[i] == ')') {
875  open--;
876  if (open == 0) {
877  bracketClose = i;
878  break;
879  }
880  }
881  }
882  if (bracketOpen == std::string::npos) {
883  throw ProcessError("Unmatched parentheses in condition " + condition + "'");
884  }
885  std::string cond2 = condition;
886  const std::string inBracket = condition.substr(bracketOpen + 1, bracketClose - bracketOpen - 1);
887  double bracketVal = evalExpression(inBracket);
888  cond2.replace(bracketOpen, bracketClose - bracketOpen + 1, toString(bracketVal));
889  return evalExpression(cond2);
890  }
891  std::vector<std::string> tokens = StringTokenizer(condition).getVector();
892  //std::cout << SIMTIME << " tokens(" << tokens.size() << ")=" << toString(tokens) << "\n";
893  if (tokens.size() == 0) {
894  throw ProcessError("Invalid empty condition '" + condition + "'");
895  } else if (tokens.size() == 1) {
896  return evalAtomicExpression(tokens[0]);
897  } else if (tokens.size() == 2) {
898  if (tokens[0] == "not") {
899  return !(bool)(evalAtomicExpression(tokens[1]));
900  } else {
901  throw ProcessError("Unsupported condition '" + condition + "'");
902  }
903  } else if (tokens.size() == 3) {
904  // infix expression
905  const double a = evalAtomicExpression(tokens[0]);
906  const double b = evalAtomicExpression(tokens[2]);
907  const std::string& o = tokens[1];
908  //std::cout << SIMTIME << " o=" << o << " a=" << a << " b=" << b << "\n";
909  return evalTernaryExpression(a, o, b, condition);
910  } else {
911  const int iEnd = (int)tokens.size() - 1;
912  for (const std::string& o : OPERATOR_PRECEDENCE) {
913  for (int i = 1; i < iEnd; i++) {
914  if (tokens[i] == o) {
915  const double val = evalTernaryExpression(
916  evalAtomicExpression(tokens[i - 1]), o,
917  evalAtomicExpression(tokens[i + 1]), condition);
918  std::vector<std::string> newTokens(tokens.begin(), tokens.begin() + (i - 1));
919  newTokens.push_back(toString(val));
920  newTokens.insert(newTokens.end(), tokens.begin() + (i + 2), tokens.end());
921  return evalExpression(toString(newTokens));
922  }
923  }
924  }
925  throw ProcessError("Parsing expressions with " + toString(tokens.size()) + " elements ('" + condition + "') is not supported");
926  }
927  return true;
928 }
929 
930 double
931 MSActuatedTrafficLightLogic::evalTernaryExpression(double a, const std::string& o, double b, const std::string& condition) const {
932  if (o == "=" || o == "==") {
933  return (double)(a == b);
934  } else if (o == "<") {
935  return (double)(a < b);
936  } else if (o == ">") {
937  return (double)(a > b);
938  } else if (o == "<=") {
939  return (double)(a <= b);
940  } else if (o == ">=") {
941  return (double)(a >= b);
942  } else if (o == "!=") {
943  return (double)(a != b);
944  } else if (o == "or" || o == "||") {
945  return (double)(a || b);
946  } else if (o == "and" || o == "&&") {
947  return (double)(a && b);
948  } else if (o == "+") {
949  return a + b;
950  } else if (o == "-") {
951  return a + b;
952  } else if (o == "*") {
953  return a * b;
954  } else if (o == "/") {
955  if (b == 0) {
956  WRITE_ERROR("Division by 0 in condition '" + condition + "'");
957  return 0;
958  }
959  return a / b;
960  } else if (o == "%") {
961  return fmod(a, b);
962  } else if (o == "**" || o == "^") {
963  return pow(a, b);
964  } else {
965  throw ProcessError("Unsupported operator '" + o + "' in condition '" + condition + "'");
966  }
967 }
968 
969 double
971  if (expr.size() == 0) {
972  throw ProcessError("Invalid empty expression");
973  } else if (expr[0] == '!') {
974  return !(bool)evalAtomicExpression(expr.substr(1));
975  } else if (expr[0] == '-') {
976  return -evalAtomicExpression(expr.substr(1));
977  } else {
978  // check for 'operator:'
979  const size_t pos = expr.find(':');
980  if (pos == std::string::npos) {
981  auto it = myConditions.find(expr);
982  if (it != myConditions.end()) {
983  // symbol lookup
984  return evalExpression(it->second);
985  } else {
986  return StringUtils::toDouble(expr);
987  }
988  } else {
989  const std::string fun = expr.substr(0, pos);
990  const std::string arg = expr.substr(pos + 1);
991  if (fun == "z") {
992  return retrieveDetExpression<MSInductLoop, SUMO_TAG_INDUCTION_LOOP>(arg, expr, true)->getTimeSinceLastDetection();
993  } else if (fun == "a") {
994  try {
995  return retrieveDetExpression<MSInductLoop, SUMO_TAG_INDUCTION_LOOP>(arg, expr, true)->getTimeSinceLastDetection() == 0;
996  } catch (ProcessError&) {
997  return retrieveDetExpression<MSE2Collector, SUMO_TAG_LANE_AREA_DETECTOR>(arg, expr, true)->getCurrentVehicleNumber() > 0;
998  }
999  } else if (fun == "g" || fun == "r") {
1000  try {
1001  int linkIndex = StringUtils::toInt(arg);
1002  if (linkIndex >= 0 && linkIndex < myNumLinks) {
1003  const std::vector<SUMOTime>& times = fun == "g" ? myLinkGreenTimes : myLinkRedTimes;
1004  if (myLastTrySwitchTime < SIMSTEP) {
1005  // times are only updated at the start of a phase where
1006  // switching is possible (i.e. not during minDur).
1007  // If somebody is looking at those values in the tracker
1008  // this would be confusing
1009  const LinkState ls = getCurrentPhaseDef().getSignalState(linkIndex);
1010  if ((fun == "g" && (ls == LINKSTATE_TL_GREEN_MAJOR || ls == LINKSTATE_TL_GREEN_MINOR))
1011  || (fun == "r" && (ls == LINKSTATE_TL_RED || ls == LINKSTATE_TL_REDYELLOW))) {
1012  const SUMOTime currentGreen = SIMSTEP - myLastTrySwitchTime;
1013  return STEPS2TIME(times[linkIndex] + currentGreen);
1014  } else {
1015  return 0;
1016  }
1017  } else {
1018  return STEPS2TIME(times[linkIndex]);
1019  }
1020  }
1021  } catch (NumberFormatException&) { }
1022  throw ProcessError("Invalid link index '" + arg + "' in expression '" + expr + "'");
1023  } else {
1024  throw ProcessError("Unsupported function '" + fun + "' in expression '" + expr + "'");
1025  }
1026  }
1027  }
1028 }
1029 
1030 
1031 std::map<std::string, double>
1033  std::map<std::string, double> result;
1034  for (auto li : myInductLoops) {
1035  result[li.loop->getID()] = li.loop->getOccupancy() > 0 ? 1 : 0;
1036  }
1037  return result;
1038 }
1039 
1040 std::map<std::string, double>
1042  std::map<std::string, double> result;
1043  for (auto item : myConditions) {
1044  result[item.first] = evalExpression(item.second);
1045  }
1046  return result;
1047 }
1048 
1049 void
1050 MSActuatedTrafficLightLogic::setParameter(const std::string& key, const std::string& value) {
1051  // some pre-defined parameters can be updated at runtime
1052  if (key == "detector-gap" || key == "passing-time" || key == "file" || key == "freq" || key == "vTypes"
1053  || StringUtils::startsWith(key, "linkMaxDur")
1054  || StringUtils::startsWith(key, "linkMinDur")) {
1055  throw InvalidArgument(key + " cannot be changed dynamically for actuated traffic light '" + getID() + "'");
1056  } else if (key == "max-gap") {
1058  // overwrite custom values
1059  for (InductLoopInfo& loopInfo : myInductLoops) {
1060  loopInfo.maxGap = myMaxGap;
1061  }
1062  } else if (key == "show-detectors") {
1064  } else if (key == "inactive-threshold") {
1066  }
1067  Parameterised::setParameter(key, value);
1068 }
1069 
1070 
1071 /****************************************************************************/
#define DEFAULT_DETECTOR_GAP
#define DEFAULT_MAX_GAP
#define DEFAULT_PASSING_TIME
#define DEFAULT_LENGTH_WITH_GAP
#define NO_DETECTOR
#define DEBUG_COND
#define DEFAULT_INACTIVE_THRESHOLD
#define DEFAULT_CURRENT_PRIORITY
#define WRITE_WARNINGF(...)
Definition: MsgHandler.h:281
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:288
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:280
std::string time2string(SUMOTime t)
convert SUMOTime to string
Definition: SUMOTime.cpp:68
SUMOTime string2time(const std::string &r)
convert string to SUMOTime
Definition: SUMOTime.cpp:45
#define STEPS2TIME(x)
Definition: SUMOTime.h:53
#define SIMSTEP
Definition: SUMOTime.h:59
#define SIMTIME
Definition: SUMOTime.h:60
#define TIME2STEPS(x)
Definition: SUMOTime.h:55
long long int SUMOTime
Definition: SUMOTime.h:32
bool noVehicles(SVCPermissions permissions)
Returns whether an edge with the given permission forbids vehicles.
@ SVC_BICYCLE
vehicle is a bicycle
@ SVC_PEDESTRIAN
pedestrian
int SVCPermissions
bitset where each bit declares whether a certain SVC may use this edge/lane
TrafficLightType
@ 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:87
T MIN2(T a, T b)
Definition: StdDefs.h:74
T MAX2(T a, T b)
Definition: StdDefs.h:80
T MAX3(T a, T b, T c)
Definition: StdDefs.h:94
std::string joinNamedToString(const std::set< T *, C > &ns, const T_BETWEEN &between)
Definition: ToString.h:303
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:269
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
static std::string checkForRelativity(const std::string &filename, const std::string &basePath)
Returns the path from a configuration so that it is accessable from the current working directory.
double myDetectorGap
The detector distance in seconds.
MSActuatedTrafficLightLogic(MSTLLogicControl &tlcontrol, const std::string &id, const std::string &programID, const SUMOTime offset, const MSSimpleTrafficLightLogic::Phases &phases, int step, SUMOTime delay, const std::map< std::string, std::string > &parameter, const std::string &basePath, const std::map< std::string, std::string > &conditions=std::map< std::string, std::string >())
Constructor.
double myMaxGap
The maximum gap to check in seconds.
void activateProgram()
called when switching programs
std::vector< SwitchingRules > mySwitchingRules
double evalAtomicExpression(const std::string &expr) const
evaluate atomic expression
int getTarget(int step)
get the green phase following step
void setParameter(const std::string &key, const std::string &value)
Sets a parameter and updates internal constants.
SUMOTime myLastTrySwitchTime
last time trySwitch was called
int getDetectorPriority(const InductLoopInfo &loopInfo) const
std::map< std::string, double > getConditions() const
return all named conditions defined for this traffic light
SUMOTime myFreq
The frequency for aggregating detector output.
SUMOTime getMinimumMinDuration(MSLane *lane) const
get the minimum min duration for all stretchable phases that affect the given lane
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
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:...
void init(NLDetectorBuilder &nb)
Initialises the tls with information about incoming lanes.
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
SUMOTime trySwitch()
Switches to the next phase.
static const std::vector< std::string > OPERATOR_PRECEDENCE
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
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.
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
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.
std::vector< InductLoopInfo > myInductLoops
std::map< std::string, std::string > myConditions
The custom switching conditions.
bool maxLinkDurationReached()
whether the current phase cannot be continued due to linkMaxDur constraints
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< SUMOTime > myLinkGreenTimes
consecutive time that the given link index has been green
std::map< std::string, double > getDetectorStates() const
retrieve all detectors used by this program
std::string myFile
The output file for generated detectors.
void initSwitchingRules()
initialize custom switching rules
int decideNextPhase()
select among candidate phases based on detector states
void changeStepAndDuration(MSTLLogicControl &tlcontrol, SUMOTime simStep, int step, SUMOTime stepDuration)
Changes the current phase and her duration.
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
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:168
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:990
virtual void addEvent(Command *operation, SUMOTime execTimeStep=-1)
Adds an Event.
static bool gUseMesoSim
Definition: MSGlobals.h:94
An unextended detector measuring at a fixed position on a fixed lane.
Definition: MSInductLoop.h:62
double getPosition() const
Returns the position of the detector on the lane.
Definition: MSInductLoop.h:94
virtual void setSpecialColor(const RGBColor *)
allows for special color in the gui version
Definition: MSInductLoop.h:295
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
Representation of a lane in the micro simulation.
Definition: MSLane.h:82
const std::vector< MSLink * > & getLinkCont() const
returns the container with all links !!!
Definition: MSLane.h:641
double getLength() const
Returns the lane's length.
Definition: MSLane.h:541
MSLane * getLogicalPredecessorLane() const
get the most likely precedecessor lane (sorted using by_connections_to_sorter). The result is cached ...
Definition: MSLane.cpp:2637
MSEdge & getEdge() const
Returns the lane's edge.
Definition: MSLane.h:674
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:174
MSDetectorControl & getDetectorControl()
Returns the detector control.
Definition: MSNet.h:439
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:318
MSEventControl * getBeginOfTimestepEvents()
Returns the event control for events executed at the begin of a time step.
Definition: MSNet.h:469
The definition of a single phase of a tls logic.
const std::string & getState() const
Returns the state within this phase.
SUMOTime maxDuration
The maximum duration of the phase.
LinkState getSignalState(int pos) const
Returns the state of the tls signal at the given position.
SUMOTime minDuration
The minimum duration of the 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.
A fixed traffic light logic.
SUMOTime getLatest() const
the maximum duratin for keeping the current phase when considering 'latestEnd'
Phases myPhases
The list of phases this logic uses.
SUMOTime getEarliest(SUMOTime prevStart) const
the minimum duration for keeping the current phase when considering 'earliestEnd'
const MSPhaseDefinition & getCurrentPhaseDef() const
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 LinkVector & getLinksAt(int i) const
Returns the list of links 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.
virtual void deactivateProgram()
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
const LaneVector & getLanesAt(int i) const
Returns the list of lanes that are controlled by the signals at the given position.
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.
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.
const std::string & getProgramID() const
Returns this tl-logic's id.
Builds detectors for microsim.
virtual MSDetectorFileOutput * createInductLoop(const std::string &id, MSLane *lane, double pos, const std::string &vTypes, int detectPersons, bool show=true)
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.
Definition: OptionsCont.cpp:58
double getDouble(const std::string &key, const double defaultValue) const
Returns the value for a given key converted to a double.
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
virtual void setParameter(const std::string &key, const std::string &value)
Sets a parameter.
const std::map< std::string, std::string > & getParametersMap() const
Returns the inner key/value map.
static const RGBColor GREEN
Definition: RGBColor.h:186
static const RGBColor RED
named colors
Definition: RGBColor.h:185
std::vector< std::string > getVector()
return vector of strings
static double toDouble(const std::string &sData)
converts a string into the double value described by it by calling the char-type converter
static bool startsWith(const std::string &str, const std::string prefix)
Checks whether a given string starts with the prefix.
static int toInt(const std::string &sData)
converts a string into the integer value described by it by calling the char-type converter,...
static bool toBool(const std::string &sData)
converts a string into the bool value described by it by calling the char-type converter