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.dev/sumo
3 // Copyright (C) 2013-2024 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 
23 #include <microsim/MSLane.h>
24 #include <microsim/MSEdge.h>
25 #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 Parameterised::Map& parameters) :
42  MSSimpleTrafficLightLogic(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 Parameterised::Map& parameters,
60  MSSOTLSensors* sensors) :
61  MSSimpleTrafficLightLogic(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  if (sensorsSelfBuilt) {
76  delete mySensors;
77 // delete myCountSensors;
78  }
79 }
80 
82 
83 }
84 
85 void
87  for (int step = 0; step < (int)getPhases().size(); step++) {
88  if (getPhase(step).isUndefined()) {
89  MsgHandler::getErrorInstance()->inform("Step " + toString(step) + " of traffic light logic " + myID + " phases declaration has its type undeclared!");
90  }
91  }
92 }
93 
94 void
96  for (int phaseStep = 0; phaseStep < (int)getPhases().size(); phaseStep++) {
97  if (getPhase(phaseStep).isTarget()) {
98  targetPhasesCTS[phaseStep] = 0;
100  targetPhasesLastSelection[phaseStep] = 0;
101  }
102  }
103 }
104 
105 void
107  for (int step = 0; step < (int)getPhases().size(); step++) {
108  if (getPhase(step).isTarget()) {
109  setStep(step);
110  lastChain = step;
111  return;
112  }
113  }
114  MsgHandler::getErrorInstance()->inform("No phase of type target found for traffic light logic " + myID + " The logic could malfunction. Check phases declaration.");
115 }
116 
117 
118 void
120 
122 
124  decayThreshold = 1;
125  }
126  if (sensorsSelfBuilt) {
127  //Building SOTLSensors
128  switch (SENSORS_TYPE) {
129  case SENSORS_TYPE_E1:
130  assert(0); // Throw exception because TLS can only handle E2 sensors
131  case SENSORS_TYPE_E2:
132 
133  //Adding Sensors to the ingoing Lanes
134 
136 
137 #ifdef SWARM_DEBUG
138  WRITE_MESSAGE("Listing lanes for TLS " + getID());
139 
140  for (int i = 0; i < lvv.size(); i++) {
141  LaneVector lv = lvv[i];
142 
143  for (int j = 0; j < lv.size(); j++) {
144  MSLane* lane = lv[j];
145  WRITE_MESSAGE(lane ->getID());
146  }
147  }
148 #endif
149 
151  ((MSSOTLE2Sensors*)mySensors)->buildSensors(myLanes, nb, getInputSensorsLength());
153  if (getParameter("USE_VEHICLE_TYPES_WEIGHTS", "0") == "1") {
154  ((MSSOTLE2Sensors*) mySensors)->setVehicleWeigths(getParameter("VEHICLE_TYPES_WEIGHTS", ""));
155  }
156 
157  //threshold speed param for tuning with irace
158  ((MSSOTLE2Sensors*)mySensors)->setSpeedThresholdParam(getSpeedThreshold());
159 
160  myCountSensors = new MSSOTLE2Sensors(myID + "Count", &(getPhases()));
163 
164  //Adding Sensors to the outgoing Lanes
165 
166  LinkVectorVector links = getLinks();
167 
168 #ifdef SWARM_DEBUG
169  WRITE_MESSAGE(TL("Listing output lanes"));
170  for (int i = 0; i < links.size(); i++) {
171  LinkVector oneLink = getLinksAt(i);
172  for (int j = 0; j < oneLink.size(); j++) {
173  MSLane* lane = oneLink[j]->getLane();
174  WRITE_MESSAGE(lane ->getID());
175  }
176  }
177 #endif
178 
179  LaneVectorVector myLaneVector;
180  LaneVector outLanes;
181  LinkVectorVector myoutLinks = getLinks();
182 
183  for (int i = 0; i < (int)links.size(); i++) {
184  LinkVector oneLink = getLinksAt(i);
185  for (int j = 0; j < (int)oneLink.size(); j++) {
186  MSLane* lane = oneLink[j]->getLane();
187  outLanes.push_back(lane);
188  }
189  }
190 
191  if (outLanes.size() > 0) {
192  myLaneVector.push_back(outLanes);
193  }
194  if (myLaneVector.size() > 0) {
195  ((MSSOTLE2Sensors*)mySensors)->buildOutSensors(myLaneVector, nb, getOutputSensorsLength());
196  myCountSensors->buildCountOutSensors(myLaneVector, nb);
197  }
198 
199  }
200  }
201 }
202 
203 
204 void
206  std::map<int, SUMOTime>::iterator phaseIterator = targetPhasesCTS.find(phaseStep);
207  if (phaseIterator != targetPhasesCTS.end()) {
208  phaseIterator->second = 0;
210  }
211 }
212 
213 void
215  SUMOTime elapsedTimeSteps = 0;
217  //Iterate over the target phase map and update CTS value for every target phase except for the one belonging to the current steps chain
218  for (std::map<int, SUMOTime>::iterator mapIterator = targetPhasesCTS.begin();
219  mapIterator != targetPhasesCTS.end();
220  mapIterator++) {
221  int chain = mapIterator->first;
222  SUMOTime oldVal = mapIterator->second;
223  if (chain != lastChain) {
224  //Get the number of timesteps since the last check for that phase
225  elapsedTimeSteps = now - lastCheckForTargetPhase[chain];
226  //Update the last check time
227  lastCheckForTargetPhase[chain] = now;
228  //Increment the CTS
229  //SWITCH between 3 counting vehicles function
230  switch (getMode()) {
231  case (0):
232  mapIterator->second += elapsedTimeSteps
233  * countVehicles(getPhase(chain)); //SUMO
234  break;
235  case (1):
236  mapIterator->second += elapsedTimeSteps
237  * countVehicles(getPhase(chain)); //COMPLEX
238  break;
239  case (2):
240  mapIterator->second = countVehicles(getPhase(chain)); //QUEUE
241  break;
242  default:
243  WRITE_ERROR(TL("Unrecognized traffic threshold calculation mode"));
244  }
245  std::ostringstream oss;
246  oss << "MSSOTLTrafficLightLogic::updateCTS->TLC " << getID() << " chain " << chain << " oldVal " << oldVal << " newVal " << mapIterator->second;
247  WRITE_MESSAGE(oss.str());
248  }
251  }
252  }
253 }
254 
255 int
257 
258  if (!phase.isTarget()) {
259  return 0;
260  }
261 
262  int accumulator = 0;
263  //Iterate over the target lanes for the current target phase to get the number of approaching vehicles
264  for (const std::string& lane : phase.getTargetLaneSet()) {
265  //SWITCH between 3 counting vehicles function
266  switch (getMode()) {
267  case (0):
268  accumulator += mySensors->countVehicles(lane); //SUMO
269  break;
270  case (1):
271  accumulator += ((MSSOTLE2Sensors*)mySensors)->estimateVehicles(lane); //COMPLEX
272  break;
273  case (2):
274  accumulator = MAX2((int)((MSSOTLE2Sensors*)mySensors)->getEstimateQueueLength(lane), accumulator); //QUEUE
275  break;
276  default:
277  WRITE_ERROR(TL("Unrecognized traffic threshold calculation mode"));
278  }
279  }
280  return accumulator;
281 }
282 
283 void
285  if (getCurrentPhaseDef().isGreenPhase()) {
287  }
288 #ifdef SWARM_DEBUG
289  std::stringstream out;
290  out << decayThreshold;
291  WRITE_MESSAGE("\n" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + "\tMSSOTLTrafficLightLogic::updateDecayThreshold():: " + out.str());
292 #endif
293 }
294 bool
296 #ifdef SWARM_DEBUG
297  // WRITE_MESSAGEF(TL("\n% tlsid=% // WRITE_MESSAGEF(TL("\n% tlsid=" + getID()), ime2string(MSNet::getInstance()->getCurrentTimeStep()) +"\tMSSOTLTrafficLightLogic::isThresholdPassed():: ", getID()), ime2string(MSNet::getInstance()->getCurrentTimeStep()) +"\tMSSOTLTrafficLightLogic::isThresholdPassed():: ");
298 
299  std::ostringstream threshold_str;
300  // threshold_str << "tlsid=" << getID() << " targetPhaseCTS size=" << targetPhasesCTS.size();
301 // threshold_str << "\n";
302  WRITE_MESSAGE(threshold_str.str());
303 #endif
304  /*
305  * if a dynamic threshold based on the exponential decrease, if passed we force the phase change
306  */
307 // double random = ((double) RandHelper::rand(RAND_MAX) / (RAND_MAX));
308  double random = RandHelper::rand();
309 // ANALYSIS_DBG(
310 #ifdef SWARM_DEBUG
312  std::ostringstream str;
313  str << time2string(MSNet::getInstance()->getCurrentTimeStep()) << "\tMSSOTLTrafficLightLogic::isThresholdPassed():: "
314  << " tlsid=" << getID() << " decayThreshold=" << decayThreshold << " random=" << random << ">" << (1 - decayThreshold)
315  << (random > (1 - decayThreshold) ? " true" : " false");
316 
317  WRITE_MESSAGE(str.str());
318  }
319 #endif
320  if (!isDecayThresholdActivated() || (isDecayThresholdActivated() && random > (1 - decayThreshold))) {
321  for (std::map<int, SUMOTime>::const_iterator iterator =
322  targetPhasesCTS.begin(); iterator != targetPhasesCTS.end();
323  iterator++) {
324 #ifdef SWARM_DEBUG
326  std::ostringstream threshold_str;
327  // threshold_str <<"\tTL " +getID()<<" time=" +time2string(step)<< "(getThreshold()= " << getThreshold()
328  // << ", targetPhaseCTS= " << iterator->second << " )" << " phase="<<getPhase(iterator->first).getState();
329  threshold_str << getCurrentPhaseDef().getState() << ";" << time2string(step) << ";" << getThreshold()
330  << ";" << iterator->second << ";" << getPhase(iterator->first).getState() << ";"
331  << iterator->first << "!=" << lastChain;
332  WRITE_MESSAGE(threshold_str.str());
333 #endif
334  //Note that the current chain is not eligible to be directly targeted again, it would be unfair
335  if ((iterator->first != lastChain) && (getThreshold() <= iterator->second)) {
336  return true;
337  }
338  }
339  return false;
340  } else {
341  return true;
342  }
343 }
344 
345 
346 SUMOTime
348  MSPhaseDefinition currentPhase = getCurrentPhaseDef();
349 
351  SUMOTime elapsed = now - currentPhase.myLastSwitch;
352 
353  return elapsed;
354 }
355 
356 
357 int
359  SUMOTime maxCTS = 0;
360  int maxLastStep = getTargetPhaseMaxLastSelection();
361  bool usedMaxCTS = false;
362  std::vector<int> equalIndexes;
363  for (std::map<int, int>::const_iterator it = targetPhasesLastSelection.begin();
364  it != targetPhasesLastSelection.end(); ++it) {
365  if (it->first != lastChain) {
366  if (maxLastStep < it->second) {
367  maxLastStep = it->second;
368  equalIndexes.clear();
369  equalIndexes.push_back(it->first);
370  } else if (maxLastStep == it->second) {
371  equalIndexes.push_back(it->first);
372  }
373  }
374  }
375  if (equalIndexes.size() == 0) {
376  usedMaxCTS = true;
377  for (std::map<int, SUMOTime>::const_iterator iterator = targetPhasesCTS.begin();
378  iterator != targetPhasesCTS.end(); ++iterator) {
379  if (iterator->first != lastChain) {
380  if (maxCTS < iterator->second) {
381  maxCTS = iterator->second;
382  equalIndexes.clear();
383  equalIndexes.push_back(iterator->first);
384  } else if (maxCTS == iterator->second) {
385  equalIndexes.push_back(iterator->first);
386  }
387  }
388  }
389  }
390 
391  std::ostringstream oss;
392  oss << "MSSOTLTrafficLightLogic::getPhaseIndexWithMaxCTS-> TLC " << getID();
393  if (usedMaxCTS) {
394  oss << " maxCTS " << maxCTS;
395  } else {
396  oss << " forcing selection since not selected for " << maxLastStep;
397  }
398  if (equalIndexes.size() == 1) {
399  oss << " phase " << equalIndexes[0];
400  WRITE_MESSAGE(oss.str());
401  return equalIndexes[0];
402  } else {
403  const int index = RandHelper::getRandomFrom(equalIndexes);
404  oss << " phases [";
405  for (std::vector<int>::const_iterator it = equalIndexes.begin(); it != equalIndexes.end(); ++it) {
406  oss << *it << ", ";
407  }
408  oss << "]. Random select " << index;
409  WRITE_MESSAGE(oss.str());
410  return index;
411  }
412 }
413 
414 int
416  MSPhaseDefinition currentPhase = getCurrentPhaseDef();
417  //If the junction was in a commit step
418  //=> go to the target step that gives green to the set with the current highest CTS
419  // and return computeReturnTime()
420  if (currentPhase.isCommit()) {
421  // decide which chain to activate. Gotta work on this
422  return getPhaseIndexWithMaxCTS();
423  }
424  if (currentPhase.isTransient()) {
425  //If the junction was in a transient step
426  //=> go to the next step and return computeReturnTime()
427  return getCurrentPhaseIndex() + 1;
428  }
429 
430  if (currentPhase.isDecisional()) {
431 
432  if (canRelease()) {
433  return getCurrentPhaseIndex() + 1;
434  }
435  }
436 
437  return getCurrentPhaseIndex();
438 }
439 
440 SUMOTime
442  if (MSNet::getInstance()->getCurrentTimeStep() % 1000 == 0) {
443  WRITE_MESSAGE("MSSOTLTrafficLightLogic::trySwitch()");
444  // To check if decideNextPhase changes the step
445  int previousStep = getCurrentPhaseIndex() ;
446 #ifdef ANALYSIS_DEBUG
447  SUMOTime elapsed = getCurrentPhaseElapsed();
448 #endif
449  // Update CTS according to sensors
450  updateCTS();
451 
452  // Invoking the function member, specialized for each SOTL logic
454  MSPhaseDefinition currentPhase = getCurrentPhaseDef();
455 
456  //At the end, check if new step started
457  if (getCurrentPhaseIndex() != previousStep) {
458  //Check if a new steps chain started
459  if (currentPhase.isTarget()) {
460  //Reset CTS for the ending steps chain
462  //Update lastTargetPhase
464  for (std::map<int, int>::iterator it = targetPhasesLastSelection.begin(); it != targetPhasesLastSelection.end(); ++ it) {
465  if (it->first == lastChain) {
466  if (it->second >= getTargetPhaseMaxLastSelection()) {
467  std::ostringstream oss;
468  oss << "Forced selection of the phase " << lastChain << " since its last selection was " << it->second << " changes ago";
469  WRITE_MESSAGE(oss.str())
470  }
471  it->second = 0;
472  } else if (it->first != previousStep) {
473  ++it->second;
474  }
475  }
477  decayThreshold = 1;
478  }
479  }
480  //Inform the sensors logic
482  //Store the time the new phase started
485  decayThreshold = 1;
486  }
487 #ifdef ANALYSIS_DEBUG
488  std::ostringstream oss;
489  oss << getID() << " from " << getPhase(previousStep).getState() << " to " << currentPhase.getState() << " after " << time2string(elapsed);
490  WRITE_MESSAGE(time2string(MSNet::getInstance()->getCurrentTimeStep()) + "\tMSSOTLTrafficLightLogic::trySwitch " + oss.str());
491 #endif
492  }
493  }
494  return computeReturnTime();
495 }
496 
498  if (getParameter("USE_PUSH_BUTTON", "0") == "0") {
499  return false;
500  }
501  const MSPhaseDefinition currentPhase = getCurrentPhaseDef();
502  if (m_pushButtons.find(currentPhase.getState()) == m_pushButtons.end()) {
503  m_pushButtons[currentPhase.getState()] = MSPedestrianPushButton::loadPushButtons(&currentPhase);
504  }
505  return MSPushButton::anyActive(m_pushButtons[currentPhase.getState()]);
506 }
507 
508 
510  step = step % myPhases.size();
511  if (myStep != step) {
512  myStep = step;
514  }
515 }
long long int SUMOTime
Definition: GUI.h:35
#define SENSORS_TYPE
#define SENSORS_TYPE_E1
#define SENSORS_TYPE_E2
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:297
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:304
#define TL(string)
Definition: MsgHandler.h:315
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition: SUMOTime.cpp:69
TrafficLightType
T MAX2(T a, T b)
Definition: StdDefs.h:82
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:84
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:182
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:320
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
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
void setStep(int step)
Forces a specific step.
SUMOTime trySwitch()
Switches to the next phase.
virtual bool canRelease()=0
int countVehicles(MSPhaseDefinition phase)
std::map< int, SUMOTime > targetPhasesCTS
virtual SUMOTime computeReturnTime()
std::map< int, int > targetPhasesLastSelection
MSSOTLTrafficLightLogic(MSTLLogicControl &tlcontrol, const std::string &id, const std::string &programID, const TrafficLightType logicType, const Phases &phases, int step, SUMOTime delay, const Parameterised::Map &parameters)
Constructor without sensors passed.
void init(NLDetectorBuilder &nb)
Initialises the tls with sensors on incoming and outgoing lanes Sensors are built in the simulation a...
A fixed traffic light logic.
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.
int getCurrentPhaseIndex() const override
Returns the current index within the program.
virtual const std::string getParameter(const std::string &key, const std::string defaultValue="") const override
gets a parameter
const Phases & getPhases() const override
Returns the phases of this tls program.
const MSPhaseDefinition & getCurrentPhaseDef() const override
Returns the definition of the current phase.
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:92
virtual void inform(std::string msg, bool addType=true)
adds a new error to the list
Definition: MsgHandler.cpp:154
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
std::map< std::string, std::string > Map
parameters map
Definition: Parameterised.h:45
static const T & getRandomFrom(const std::vector< T > &v, SumoRNG *rng=nullptr)
Returns a random element from the given vector.
Definition: RandHelper.h:206
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1)
Definition: RandHelper.cpp:94