Eclipse SUMO - Simulation of Urban MObility
MSSOTLTrafficLightLogic.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2013-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 /****************************************************************************/
20 // The base abstract class for SOTL logics
21 /****************************************************************************/
22 
24 #include "../MSLane.h"
25 #include "../MSEdge.h"
26 #include "MSPushButton.h"
27 //#define SWARM_DEBUG
28 //#define ANALYSIS_DEBUG
29 
30 // ===========================================================================
31 // member method definitions
32 // ===========================================================================
34  MSTLLogicControl& tlcontrol,
35  const std::string& id,
36  const std::string& programID,
37  const TrafficLightType logicType,
38  const Phases& phases,
39  int step,
40  SUMOTime delay,
41  const std::map<std::string, std::string>& parameters)
42  : MSPhasedTrafficLightLogic(tlcontrol, id, programID, 0, logicType, phases, step, delay, parameters) {
43  this->mySensors = nullptr;
44  this->myCountSensors = nullptr;
45  sensorsSelfBuilt = true;
46  checkPhases();
47  setupCTS();
49 }
50 
52  MSTLLogicControl& tlcontrol,
53  const std::string& id,
54  const std::string& programID,
55  const TrafficLightType logicType,
56  const Phases& phases,
57  int step,
58  SUMOTime delay,
59  const std::map<std::string, std::string>& parameters,
60  MSSOTLSensors* sensors)
61  : MSPhasedTrafficLightLogic(tlcontrol, id, programID, 0, logicType, phases, step, delay, parameters) {
62  this->mySensors = sensors;
63  sensorsSelfBuilt = false;
64  checkPhases();
65  setupCTS();
67 }
68 
70  for (PhasePushButtons::iterator mapIt = m_pushButtons.begin(); mapIt != m_pushButtons.end(); ++mapIt)
71  for (std::vector<MSPushButton*>::iterator vIt = mapIt->second.begin(); vIt != mapIt->second.end(); ++vIt) {
72  delete *vIt;
73  }
74  m_pushButtons.clear();
75  for (int i = 0; i < (int)myPhases.size(); i++) {
76  delete myPhases[i];
77  }
78  if (sensorsSelfBuilt) {
79  delete mySensors;
80 // delete myCountSensors;
81  }
82 }
83 
85 
86 }
87 
88 void
90  for (int step = 0; step < (int)getPhases().size(); step++) {
91  if (getPhase(step).isUndefined()) {
92  MsgHandler::getErrorInstance()->inform("Step " + toString(step) + " of traffic light logic " + myID + " phases declaration has its type undeclared!");
93  }
94  }
95 }
96 
97 void
99  for (int phaseStep = 0; phaseStep < (int)getPhases().size(); phaseStep++) {
100  if (getPhase(phaseStep).isTarget()) {
101  targetPhasesCTS[phaseStep] = 0;
103  targetPhasesLastSelection[phaseStep] = 0;
104  }
105  }
106 }
107 
108 void
110  for (int step = 0; step < (int)getPhases().size(); step++) {
111  if (getPhase(step).isTarget()) {
112  setStep(step);
113  lastChain = step;
114  return;
115  }
116  }
117  MsgHandler::getErrorInstance()->inform("No phase of type target found for traffic light logic " + myID + " The logic could malfunction. Check phases declaration.");
118 }
119 
120 
121 void
123 
125 
127  decayThreshold = 1;
128  }
129  if (sensorsSelfBuilt) {
130  //Building SOTLSensors
131  switch (SENSORS_TYPE) {
132  case SENSORS_TYPE_E1:
133  assert(0); // Throw exception because TLS can only handle E2 sensors
134  case SENSORS_TYPE_E2:
135 
136  //Adding Sensors to the ingoing Lanes
137 
139 
140 #ifdef SWARM_DEBUG
141  WRITE_MESSAGE("Listing lanes for TLS " + getID());
142 
143  for (int i = 0; i < lvv.size(); i++) {
144  LaneVector lv = lvv[i];
145 
146  for (int j = 0; j < lv.size(); j++) {
147  MSLane* lane = lv[j];
148  WRITE_MESSAGE(lane ->getID());
149  }
150  }
151 #endif
152 
154  ((MSSOTLE2Sensors*)mySensors)->buildSensors(myLanes, nb, getInputSensorsLength());
156  if (getParameter("USE_VEHICLE_TYPES_WEIGHTS", "0") == "1") {
157  ((MSSOTLE2Sensors*) mySensors)->setVehicleWeigths(getParameter("VEHICLE_TYPES_WEIGHTS", ""));
158  }
159 
160  //threshold speed param for tuning with irace
161  ((MSSOTLE2Sensors*)mySensors)->setSpeedThresholdParam(getSpeedThreshold());
162 
163  myCountSensors = new MSSOTLE2Sensors(myID + "Count", &(getPhases()));
166 
167  //Adding Sensors to the outgoing Lanes
168 
169  LinkVectorVector links = getLinks();
170 
171 #ifdef SWARM_DEBUG
172  WRITE_MESSAGE("Listing output lanes");
173  for (int i = 0; i < links.size(); i++) {
174  LinkVector oneLink = getLinksAt(i);
175  for (int j = 0; j < oneLink.size(); j++) {
176  MSLane* lane = oneLink[j]->getLane();
177  WRITE_MESSAGE(lane ->getID());
178  }
179  }
180 #endif
181 
182  LaneVectorVector myLaneVector;
183  LaneVector outLanes;
184  LinkVectorVector myoutLinks = getLinks();
185 
186  for (int i = 0; i < (int)links.size(); i++) {
187  LinkVector oneLink = getLinksAt(i);
188  for (int j = 0; j < (int)oneLink.size(); j++) {
189  MSLane* lane = oneLink[j]->getLane();
190  outLanes.push_back(lane);
191  }
192  }
193 
194  if (outLanes.size() > 0) {
195  myLaneVector.push_back(outLanes);
196  }
197  if (myLaneVector.size() > 0) {
198  ((MSSOTLE2Sensors*)mySensors)->buildOutSensors(myLaneVector, nb, getOutputSensorsLength());
199  myCountSensors->buildCountOutSensors(myLaneVector, nb);
200  }
201 
202  }
203  }
204 }
205 
206 
207 void
209  std::map<int, SUMOTime>::iterator phaseIterator = targetPhasesCTS.find(phaseStep);
210  if (phaseIterator != targetPhasesCTS.end()) {
211  phaseIterator->second = 0;
213  }
214 }
215 
216 void
218  SUMOTime elapsedTimeSteps = 0;
220  //Iterate over the target phase map and update CTS value for every target phase except for the one belonging to the current steps chain
221  for (std::map<int, SUMOTime>::iterator mapIterator = targetPhasesCTS.begin();
222  mapIterator != targetPhasesCTS.end();
223  mapIterator++) {
224  int chain = mapIterator->first;
225  SUMOTime oldVal = mapIterator->second;
226  if (chain != lastChain) {
227  //Get the number of timesteps since the last check for that phase
228  elapsedTimeSteps = now - lastCheckForTargetPhase[chain];
229  //Update the last check time
230  lastCheckForTargetPhase[chain] = now;
231  //Increment the CTS
232  //SWITCH between 3 counting vehicles function
233  switch (getMode()) {
234  case (0):
235  mapIterator->second += elapsedTimeSteps
236  * countVehicles(getPhase(chain)); //SUMO
237  break;
238  case (1):
239  mapIterator->second += elapsedTimeSteps
240  * countVehicles(getPhase(chain)); //COMPLEX
241  break;
242  case (2):
243  mapIterator->second = countVehicles(getPhase(chain)); //QUEUE
244  break;
245  default:
246  WRITE_ERROR("Unrecognized traffic threshold calculation mode");
247  }
248  std::ostringstream oss;
249  oss << "MSSOTLTrafficLightLogic::updateCTS->TLC " << getID() << " chain " << chain << " oldVal " << oldVal << " newVal " << mapIterator->second;
250  WRITE_MESSAGE(oss.str());
251  }
254  }
255  }
256 }
257 
258 int
260 
261  if (!phase.isTarget()) {
262  return 0;
263  }
264 
265  int accumulator = 0;
266  //Iterate over the target lanes for the current target phase to get the number of approaching vehicles
267  for (const std::string& lane : phase.getTargetLaneSet()) {
268  //SWITCH between 3 counting vehicles function
269  switch (getMode()) {
270  case (0):
271  accumulator += mySensors->countVehicles(lane); //SUMO
272  break;
273  case (1):
274  accumulator += ((MSSOTLE2Sensors*)mySensors)->estimateVehicles(lane); //COMPLEX
275  break;
276  case (2):
277  accumulator = MAX2((int)((MSSOTLE2Sensors*)mySensors)->getEstimateQueueLength(lane), accumulator); //QUEUE
278  break;
279  default:
280  WRITE_ERROR("Unrecognized traffic threshold calculation mode");
281  }
282  }
283  return accumulator;
284 }
285 
286 void
288  if (getCurrentPhaseDef().isGreenPhase()) {
290  }
291 #ifdef SWARM_DEBUG
292  std::stringstream out;
293  out << decayThreshold;
294  WRITE_MESSAGE("\n" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + "\tMSSOTLTrafficLightLogic::updateDecayThreshold():: " + out.str());
295 #endif
296 }
297 bool
299 #ifdef SWARM_DEBUG
300  // WRITE_MESSAGE("\n" +time2string(MSNet::getInstance()->getCurrentTimeStep()) +"\tMSSOTLTrafficLightLogic::isThresholdPassed():: " + " tlsid=" + getID());
301 
302  std::ostringstream threshold_str;
303  // threshold_str << "tlsid=" << getID() << " targetPhaseCTS size=" << targetPhasesCTS.size();
304 // threshold_str << "\n";
305  WRITE_MESSAGE(threshold_str.str());
306 #endif
307  /*
308  * if a dynamic threshold based on the exponential decrease, if passed we force the phase change
309  */
310 // double random = ((double) RandHelper::rand(RAND_MAX) / (RAND_MAX));
311  double random = RandHelper::rand();
312 // ANALYSIS_DBG(
313 #ifdef SWARM_DEBUG
315  std::ostringstream str;
316  str << time2string(MSNet::getInstance()->getCurrentTimeStep()) << "\tMSSOTLTrafficLightLogic::isThresholdPassed():: "
317  << " tlsid=" << getID() << " decayThreshold=" << decayThreshold << " random=" << random << ">" << (1 - decayThreshold)
318  << (random > (1 - decayThreshold) ? " true" : " false");
319 
320  WRITE_MESSAGE(str.str());
321  }
322 #endif
323  if (!isDecayThresholdActivated() || (isDecayThresholdActivated() && random > (1 - decayThreshold))) {
324  for (std::map<int, SUMOTime>::const_iterator iterator =
325  targetPhasesCTS.begin(); iterator != targetPhasesCTS.end();
326  iterator++) {
327 #ifdef SWARM_DEBUG
329  std::ostringstream threshold_str;
330  // threshold_str <<"\tTL " +getID()<<" time=" +time2string(step)<< "(getThreshold()= " << getThreshold()
331  // << ", targetPhaseCTS= " << iterator->second << " )" << " phase="<<getPhase(iterator->first).getState();
332  threshold_str << getCurrentPhaseDef().getState() << ";" << time2string(step) << ";" << getThreshold()
333  << ";" << iterator->second << ";" << getPhase(iterator->first).getState() << ";"
334  << iterator->first << "!=" << lastChain;
335  WRITE_MESSAGE(threshold_str.str());
336 #endif
337  //Note that the current chain is not eligible to be directly targeted again, it would be unfair
338  if ((iterator->first != lastChain) && (getThreshold() <= iterator->second)) {
339  return true;
340  }
341  }
342  return false;
343  } else {
344  return true;
345  }
346 }
347 
348 
349 SUMOTime
351  MSPhaseDefinition currentPhase = getCurrentPhaseDef();
352 
354  SUMOTime elapsed = now - currentPhase.myLastSwitch;
355 
356  return elapsed;
357 }
358 
359 
360 int
362  SUMOTime maxCTS = 0;
363  int maxLastStep = getTargetPhaseMaxLastSelection();
364  bool usedMaxCTS = false;
365  std::vector<int> equalIndexes;
366  for (std::map<int, int>::const_iterator it = targetPhasesLastSelection.begin();
367  it != targetPhasesLastSelection.end(); ++it) {
368  if (it->first != lastChain) {
369  if (maxLastStep < it->second) {
370  maxLastStep = it->second;
371  equalIndexes.clear();
372  equalIndexes.push_back(it->first);
373  } else if (maxLastStep == it->second) {
374  equalIndexes.push_back(it->first);
375  }
376  }
377  }
378  if (equalIndexes.size() == 0) {
379  usedMaxCTS = true;
380  for (std::map<int, SUMOTime>::const_iterator iterator = targetPhasesCTS.begin();
381  iterator != targetPhasesCTS.end(); ++iterator) {
382  if (iterator->first != lastChain) {
383  if (maxCTS < iterator->second) {
384  maxCTS = iterator->second;
385  equalIndexes.clear();
386  equalIndexes.push_back(iterator->first);
387  } else if (maxCTS == iterator->second) {
388  equalIndexes.push_back(iterator->first);
389  }
390  }
391  }
392  }
393 
394  std::ostringstream oss;
395  oss << "MSSOTLTrafficLightLogic::getPhaseIndexWithMaxCTS-> TLC " << getID();
396  if (usedMaxCTS) {
397  oss << " maxCTS " << maxCTS;
398  } else {
399  oss << " forcing selection since not selected for " << maxLastStep;
400  }
401  if (equalIndexes.size() == 1) {
402  oss << " phase " << equalIndexes[0];
403  WRITE_MESSAGE(oss.str());
404  return equalIndexes[0];
405  } else {
406  const int index = RandHelper::getRandomFrom(equalIndexes);
407  oss << " phases [";
408  for (std::vector<int>::const_iterator it = equalIndexes.begin(); it != equalIndexes.end(); ++it) {
409  oss << *it << ", ";
410  }
411  oss << "]. Random select " << index;
412  WRITE_MESSAGE(oss.str());
413  return index;
414  }
415 }
416 
417 int
419  MSPhaseDefinition currentPhase = getCurrentPhaseDef();
420  //If the junction was in a commit step
421  //=> go to the target step that gives green to the set with the current highest CTS
422  // and return computeReturnTime()
423  if (currentPhase.isCommit()) {
424  // decide which chain to activate. Gotta work on this
425  return getPhaseIndexWithMaxCTS();
426  }
427  if (currentPhase.isTransient()) {
428  //If the junction was in a transient step
429  //=> go to the next step and return computeReturnTime()
430  return getCurrentPhaseIndex() + 1;
431  }
432 
433  if (currentPhase.isDecisional()) {
434 
435  if (canRelease()) {
436  return getCurrentPhaseIndex() + 1;
437  }
438  }
439 
440  return getCurrentPhaseIndex();
441 }
442 
443 SUMOTime
445  if (MSNet::getInstance()->getCurrentTimeStep() % 1000 == 0) {
446  WRITE_MESSAGE("MSSOTLTrafficLightLogic::trySwitch()")
447  // To check if decideNextPhase changes the step
448  int previousStep = getCurrentPhaseIndex() ;
449 #ifdef ANALYSIS_DEBUG
450  SUMOTime elapsed = getCurrentPhaseElapsed();
451 #endif
452  // Update CTS according to sensors
453  updateCTS();
454 
455  // Invoking the function member, specialized for each SOTL logic
457  MSPhaseDefinition currentPhase = getCurrentPhaseDef();
458 
459  //At the end, check if new step started
460  if (getCurrentPhaseIndex() != previousStep) {
461  //Check if a new steps chain started
462  if (currentPhase.isTarget()) {
463  //Reset CTS for the ending steps chain
465  //Update lastTargetPhase
467  for (std::map<int, int>::iterator it = targetPhasesLastSelection.begin(); it != targetPhasesLastSelection.end(); ++ it) {
468  if (it->first == lastChain) {
469  if (it->second >= getTargetPhaseMaxLastSelection()) {
470  std::ostringstream oss;
471  oss << "Forced selection of the phase " << lastChain << " since its last selection was " << it->second << " changes ago";
472  WRITE_MESSAGE(oss.str())
473  }
474  it->second = 0;
475  } else if (it->first != previousStep) {
476  ++it->second;
477  }
478  }
480  decayThreshold = 1;
481  }
482  }
483  //Inform the sensors logic
485  //Store the time the new phase started
488  decayThreshold = 1;
489  }
490 #ifdef ANALYSIS_DEBUG
491  std::ostringstream oss;
492  oss << getID() << " from " << getPhase(previousStep).getState() << " to " << currentPhase.getState() << " after " << time2string(elapsed);
493  WRITE_MESSAGE(time2string(MSNet::getInstance()->getCurrentTimeStep()) + "\tMSSOTLTrafficLightLogic::trySwitch " + oss.str());
494 #endif
495  }
496  }
497  return computeReturnTime();
498 }
499 
501  if (getParameter("USE_PUSH_BUTTON", "0") == "0") {
502  return false;
503  }
504  const MSPhaseDefinition currentPhase = getCurrentPhaseDef();
505  if (m_pushButtons.find(currentPhase.getState()) == m_pushButtons.end()) {
506  m_pushButtons[currentPhase.getState()] = MSPedestrianPushButton::loadPushButtons(&currentPhase);
507  }
508  return MSPushButton::anyActive(m_pushButtons[currentPhase.getState()]);
509 }
510 
#define SENSORS_TYPE
#define SENSORS_TYPE_E1
#define SENSORS_TYPE_E2
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:282
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:288
std::string time2string(SUMOTime t)
convert SUMOTime to string
Definition: SUMOTime.cpp:68
long long int SUMOTime
Definition: SUMOTime.h:32
TrafficLightType
T MAX2(T a, T b)
Definition: StdDefs.h:80
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
Representation of a lane in the micro simulation.
Definition: MSLane.h:82
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:174
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:318
static std::vector< MSPushButton * > loadPushButtons(const MSPhaseDefinition *)
Loads all the pushbuttons for all the controlled lanes of a stage.
The definition of a single phase of a tls logic.
const std::string & getState() const
Returns the state within this phase.
bool isTransient() const
bool isUndefined() const
const std::vector< std::string > & getTargetLaneSet() const
SUMOTime myLastSwitch
Stores the timestep of the last on-switched of the phase.
bool isDecisional() const
A fixed traffic light logic.
Phases myPhases
The list of phases this logic uses.
const Phases & getPhases() const
Returns the phases of this tls program.
int getCurrentPhaseIndex() const
Returns the current index within the program.
const MSPhaseDefinition & getPhase(int givenstep) const
Returns the definition of the phase from the given position within the plan.
void setStep(int step)
Forces a specific step.
const MSPhaseDefinition & getCurrentPhaseDef() const
Returns the definition of the current phase.
static bool anyActive(const std::vector< MSPushButton * > &)
Checks if any pushbutton in the vector is active.
void buildCountOutSensors(MSTrafficLightLogic::LaneVectorVector controlledLanes, NLDetectorBuilder &nb)
void buildCountSensors(MSTrafficLightLogic::LaneVectorVector controlledLanes, NLDetectorBuilder &nb)
virtual void stepChanged(int newStep)
virtual int countVehicles(MSLane *lane)=0
std::map< int, SUMOTime > lastCheckForTargetPhase
SUMOTime trySwitch()
Switches to the next phase.
virtual bool canRelease()=0
int countVehicles(MSPhaseDefinition phase)
MSSOTLTrafficLightLogic(MSTLLogicControl &tlcontrol, const std::string &id, const std::string &programID, const TrafficLightType logicType, const Phases &phases, int step, SUMOTime delay, const std::map< std::string, std::string > &parameters)
Constructor without sensors passed.
std::map< int, SUMOTime > targetPhasesCTS
virtual SUMOTime computeReturnTime()
std::map< int, int > targetPhasesLastSelection
void init(NLDetectorBuilder &nb)
Initialises the tls with sensors on incoming and outgoing lanes Sensors are built in the simulation a...
A class that stores and controls tls and switching of their programs.
const LinkVector & getLinksAt(int i) const
Returns the list of links that are controlled by the signals at the given position.
std::vector< LaneVector > LaneVectorVector
Definition of a list that holds lists of lanes that do have the same attribute.
std::vector< MSLane * > LaneVector
Definition of the list of arrival lanes subjected to this tls.
const LaneVectorVector & getLaneVectors() const
Returns the list of lists of all lanes controlled by this tls.
const LinkVectorVector & getLinks() const
Returns the list of lists of all affected links.
LaneVectorVector myLanes
The list of LaneVectors; each vector contains the incoming lanes that belong to the same link index.
std::vector< MSPhaseDefinition * > Phases
Definition of a list of phases, being the junction logic.
std::vector< LinkVector > LinkVectorVector
Definition of a list that holds lists of links that do have the same attribute.
std::vector< MSLink * > LinkVector
Definition of the list of links that are subjected to this tls.
virtual void init(NLDetectorBuilder &nb)
Initialises the tls with information about incoming lanes.
static MsgHandler * getErrorInstance()
Returns the instance to add errors to.
Definition: MsgHandler.cpp:80
virtual void inform(std::string msg, bool addType=true)
adds a new error to the list
Definition: MsgHandler.cpp:117
Builds detectors for microsim.
std::string myID
The name of the object.
Definition: Named.h:125
const std::string & getID() const
Returns the id.
Definition: Named.h:74
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
static const T & getRandomFrom(const std::vector< T > &v, SumoRNG *rng=nullptr)
Returns a random element from the given vector.
Definition: RandHelper.h:208
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
Definition: RandHelper.h:119