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-2020 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 
28 #if 1
29 #define ANALYSIS_DBG(X) {X}
30 #else
31 #define ANALYSIS_DBG(X) DBG(X)
32 #endif
33 // ===========================================================================
34 // member method definitions
35 // ===========================================================================
37  MSTLLogicControl& tlcontrol,
38  const std::string& id,
39  const std::string& programID,
40  const TrafficLightType logicType,
41  const Phases& phases,
42  int step,
43  SUMOTime delay,
44  const std::map<std::string, std::string>& parameters)
45  : MSPhasedTrafficLightLogic(tlcontrol, id, programID, logicType, phases, step, delay, parameters) {
46  this->mySensors = nullptr;
47  this->myCountSensors = nullptr;
48  sensorsSelfBuilt = true;
49  checkPhases();
50  setupCTS();
52 }
53 
55  MSTLLogicControl& tlcontrol,
56  const std::string& id,
57  const std::string& programID,
58  const TrafficLightType logicType,
59  const Phases& phases,
60  int step,
61  SUMOTime delay,
62  const std::map<std::string, std::string>& parameters,
63  MSSOTLSensors* sensors)
64  : MSPhasedTrafficLightLogic(tlcontrol, id, programID, logicType, phases, step, delay, parameters) {
65  this->mySensors = sensors;
66  sensorsSelfBuilt = false;
67  checkPhases();
68  setupCTS();
70 }
71 
73  for (PhasePushButtons::iterator mapIt = m_pushButtons.begin(); mapIt != m_pushButtons.end(); ++mapIt)
74  for (std::vector<MSPushButton*>::iterator vIt = mapIt->second.begin(); vIt != mapIt->second.end(); ++vIt) {
75  delete *vIt;
76  }
77  m_pushButtons.clear();
78  for (int i = 0; i < (int)myPhases.size(); i++) {
79  delete myPhases[i];
80  }
81  if (sensorsSelfBuilt) {
82  delete mySensors;
83 // delete myCountSensors;
84  }
85 }
86 
88 
89 }
90 
91 void
93  for (int step = 0; step < (int)getPhases().size(); step++) {
94  if (getPhase(step).isUndefined()) {
95  MsgHandler::getErrorInstance()->inform("Step " + toString(step) + " of traffic light logic " + myID + " phases declaration has its type undeclared!");
96  }
97  }
98 }
99 
100 void
102  for (int phaseStep = 0; phaseStep < (int)getPhases().size(); phaseStep++) {
103  if (getPhase(phaseStep).isTarget()) {
104  targetPhasesCTS[phaseStep] = 0;
106  targetPhasesLastSelection[phaseStep] = 0;
107  }
108  }
109 }
110 
111 void
113  for (int step = 0; step < (int)getPhases().size(); step++) {
114  if (getPhase(step).isTarget()) {
115  setStep(step);
116  lastChain = step;
117  return;
118  }
119  }
120  MsgHandler::getErrorInstance()->inform("No phase of type target found for traffic light logic " + myID + " The logic could malfunction. Check phases declaration.");
121 }
122 
123 
124 void
126 
128 
130  decayThreshold = 1;
131  }
132  if (sensorsSelfBuilt) {
133  //Building SOTLSensors
134  switch (SENSORS_TYPE) {
135  case SENSORS_TYPE_E1:
136  assert(0); // Throw exception because TLS can only handle E2 sensors
137  case SENSORS_TYPE_E2:
138 
139  //Adding Sensors to the ingoing Lanes
140 
142 
143  DBG(
144  WRITE_MESSAGE("Listing lanes for TLS " + getID());
145 
146  for (int i = 0; i < lvv.size(); i++) {
147  LaneVector lv = lvv[i];
148 
149  for (int j = 0; j < lv.size(); j++) {
150  MSLane* lane = lv[j];
151  WRITE_MESSAGE(lane ->getID());
152  }
153  }
154  )
155 
159  if (getParameter("USE_VEHICLE_TYPES_WEIGHTS", "0") == "1") {
160  ((MSSOTLE2Sensors*) mySensors)->setVehicleWeigths(getParameter("VEHICLE_TYPES_WEIGHTS", ""));
161  }
162 
163  //threshold speed param for tuning with irace
164  ((MSSOTLE2Sensors*)mySensors)->setSpeedThresholdParam(getSpeedThreshold());
165 
166  myCountSensors = new MSSOTLE2Sensors(myID + "Count", &(getPhases()));
169 
170  //Adding Sensors to the outgoing Lanes
171 
173 
174 
175  DBG(
176  WRITE_MESSAGE("Listing output lanes");
177  for (int i = 0; i < myLinks.size(); i++) {
178  LinkVector oneLink = getLinksAt(i);
179 
180  for (int j = 0; j < oneLink.size(); j++) {
181 
182  MSLane* lane = oneLink[j]->getLane();
183  WRITE_MESSAGE(lane ->getID());
184 
185  }
186  }
187  )
188 
189 
190  LaneVectorVector myLaneVector;
191 
192  LaneVector outLanes;
193  LinkVectorVector myoutLinks = getLinks();
194 
195  for (int i = 0; i < (int)myLinks.size(); i++) {
196  LinkVector oneLink = getLinksAt(i);
197  for (int j = 0; j < (int)oneLink.size(); j++) {
198  MSLane* lane = oneLink[j]->getLane();
199  outLanes.push_back(lane);
200  }
201  }
202 
203  if (outLanes.size() > 0) {
204  myLaneVector.push_back(outLanes);
205  }
206  if (myLaneVector.size() > 0) {
207  ((MSSOTLE2Sensors*)mySensors)->buildOutSensors(myLaneVector, nb, getOutputSensorsLength());
208  myCountSensors->buildCountOutSensors(myLaneVector, nb);
209  }
210 
211  }
212  }
213 }
214 
215 
216 void
218  std::map<int, SUMOTime>::iterator phaseIterator = targetPhasesCTS.find(phaseStep);
219  if (phaseIterator != targetPhasesCTS.end()) {
220  phaseIterator->second = 0;
222  }
223 }
224 
225 void
227  SUMOTime elapsedTimeSteps = 0;
229  //Iterate over the target phase map and update CTS value for every target phase except for the one belonging to the current steps chain
230  for (std::map<int, SUMOTime>::iterator mapIterator = targetPhasesCTS.begin();
231  mapIterator != targetPhasesCTS.end();
232  mapIterator++) {
233  int chain = mapIterator->first;
234  SUMOTime oldVal = mapIterator->second;
235  if (chain != lastChain) {
236  //Get the number of timesteps since the last check for that phase
237  elapsedTimeSteps = now - lastCheckForTargetPhase[chain];
238  //Update the last check time
239  lastCheckForTargetPhase[chain] = now;
240  //Increment the CTS
241  //SWITCH between 3 counting vehicles function
242  switch (getMode()) {
243  case (0):
244  mapIterator->second += elapsedTimeSteps
245  * countVehicles(getPhase(chain)); //SUMO
246  break;
247  case (1):
248  mapIterator->second += elapsedTimeSteps
249  * countVehicles(getPhase(chain)); //COMPLEX
250  break;
251  case (2):
252  mapIterator->second = countVehicles(getPhase(chain)); //QUEUE
253  break;
254  default:
255  WRITE_ERROR("Unrecognized traffic threshold calculation mode");
256  }
257  std::ostringstream oss;
258  oss << "MSSOTLTrafficLightLogic::updateCTS->TLC " << getID() << " chain " << chain << " oldVal " << oldVal << " newVal " << mapIterator->second;
259  WRITE_MESSAGE(oss.str());
260  }
263  }
264  }
265 }
266 
267 int
269 
270  if (!phase.isTarget()) {
271  return 0;
272  }
273 
274  int accumulator = 0;
275  //Iterate over the target lanes for the current target phase to get the number of approaching vehicles
277  for (MSPhaseDefinition::LaneIdVector::const_iterator laneIterator = targetLanes.begin(); laneIterator != targetLanes.end(); laneIterator++) {
278  //SWITCH between 3 counting vehicles function
279  switch (getMode()) {
280  case (0):
281  accumulator += mySensors->countVehicles((*laneIterator)); //SUMO
282  break;
283  case (1):
284  accumulator += ((MSSOTLE2Sensors*)mySensors)->estimateVehicles((*laneIterator)); //COMPLEX
285  break;
286  case (2):
287  accumulator = MAX2((int)((MSSOTLE2Sensors*)mySensors)->getEstimateQueueLength((*laneIterator)), accumulator); //QUEUE
288  break;
289  default:
290  WRITE_ERROR("Unrecognized traffic threshold calculation mode");
291  }
292  }
293  return accumulator;
294 }
295 
296 void
298  if (getCurrentPhaseDef().isGreenPhase()) {
300  }
301 // ANALYSIS_DBG(
302  DBG(
303  std::stringstream out;
304  out << decayThreshold;
305  WRITE_MESSAGE("\n" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + "\tMSSOTLTrafficLightLogic::updateDecayThreshold():: " + out.str());
306  )
307 }
308 bool
310 
311  DBG(
312  // WRITE_MESSAGE("\n" +time2string(MSNet::getInstance()->getCurrentTimeStep()) +"\tMSSOTLTrafficLightLogic::isThresholdPassed():: " + " tlsid=" + getID());
313 
314  std::ostringstream threshold_str;
315  // threshold_str << "tlsid=" << getID() << " targetPhaseCTS size=" << targetPhasesCTS.size();
316 // threshold_str << "\n";
317  WRITE_MESSAGE(threshold_str.str());
318  )
319  /*
320  * if a dynamic threshold based on the exponential decrease, if passed we force the phase change
321  */
322 // double random = ((double) RandHelper::rand(RAND_MAX) / (RAND_MAX));
323  double random = RandHelper::rand();
324 // ANALYSIS_DBG(
325  DBG(
327  std::ostringstream str;
328  str << time2string(MSNet::getInstance()->getCurrentTimeStep()) << "\tMSSOTLTrafficLightLogic::isThresholdPassed():: "
329  << " tlsid=" << getID() << " decayThreshold=" << decayThreshold << " random=" << random << ">" << (1 - decayThreshold)
330  << (random > (1 - decayThreshold) ? " true" : " false");
331 
332  WRITE_MESSAGE(str.str());
333  }
334  )
335  if (!isDecayThresholdActivated() || (isDecayThresholdActivated() && random > (1 - decayThreshold))) {
336  for (std::map<int, SUMOTime>::const_iterator iterator =
337  targetPhasesCTS.begin(); iterator != targetPhasesCTS.end();
338  iterator++) {
339  DBG(
340  SUMOTime step = MSNet::getInstance()->getCurrentTimeStep();
341  std::ostringstream threshold_str;
342  // threshold_str <<"\tTL " +getID()<<" time " +time2string(step)<< "(getThreshold()= " << getThreshold()
343  // << ", targetPhaseCTS= " << iterator->second << " )" << " phase="<<getPhase(iterator->first).getState();
344  threshold_str << getCurrentPhaseDef().getState() << ";" << time2string(step) << ";" << getThreshold()
345  << ";" << iterator->second << ";" << getPhase(iterator->first).getState() << ";"
346  << iterator->first << "!=" << lastChain;
347  WRITE_MESSAGE(threshold_str.str());
348  );
349  //Note that the current chain is not eligible to be directly targeted again, it would be unfair
350  if ((iterator->first != lastChain) && (getThreshold() <= iterator->second)) {
351  return true;
352  }
353  }
354  return false;
355  } else {
356  return true;
357  }
358 }
359 
360 
361 SUMOTime
363  MSPhaseDefinition currentPhase = getCurrentPhaseDef();
364 
366  SUMOTime elapsed = now - currentPhase.myLastSwitch;
367 
368  return elapsed;
369 }
370 
371 
372 int
374  SUMOTime maxCTS = 0;
375  int maxLastStep = getTargetPhaseMaxLastSelection();
376  bool usedMaxCTS = false;
377  std::vector<int> equalIndexes;
378  for (std::map<int, int>::const_iterator it = targetPhasesLastSelection.begin();
379  it != targetPhasesLastSelection.end(); ++it) {
380  if (it->first != lastChain) {
381  if (maxLastStep < it->second) {
382  maxLastStep = it->second;
383  equalIndexes.clear();
384  equalIndexes.push_back(it->first);
385  } else if (maxLastStep == it->second) {
386  equalIndexes.push_back(it->first);
387  }
388  }
389  }
390  if (equalIndexes.size() == 0) {
391  usedMaxCTS = true;
392  for (std::map<int, SUMOTime>::const_iterator iterator = targetPhasesCTS.begin();
393  iterator != targetPhasesCTS.end(); ++iterator) {
394  if (iterator->first != lastChain) {
395  if (maxCTS < iterator->second) {
396  maxCTS = iterator->second;
397  equalIndexes.clear();
398  equalIndexes.push_back(iterator->first);
399  } else if (maxCTS == iterator->second) {
400  equalIndexes.push_back(iterator->first);
401  }
402  }
403  }
404  }
405 
406  std::ostringstream oss;
407  oss << "MSSOTLTrafficLightLogic::getPhaseIndexWithMaxCTS-> TLC " << getID();
408  if (usedMaxCTS) {
409  oss << " maxCTS " << maxCTS;
410  } else {
411  oss << " forcing selection since not selected for " << maxLastStep;
412  }
413  if (equalIndexes.size() == 1) {
414  oss << " phase " << equalIndexes[0];
415  WRITE_MESSAGE(oss.str());
416  return equalIndexes[0];
417  } else {
418  const int index = RandHelper::getRandomFrom(equalIndexes);
419  oss << " phases [";
420  for (std::vector<int>::const_iterator it = equalIndexes.begin(); it != equalIndexes.end(); ++it) {
421  oss << *it << ", ";
422  }
423  oss << "]. Random select " << index;
424  WRITE_MESSAGE(oss.str());
425  return index;
426  }
427 }
428 
429 int
431  MSPhaseDefinition currentPhase = getCurrentPhaseDef();
432  //If the junction was in a commit step
433  //=> go to the target step that gives green to the set with the current highest CTS
434  // and return computeReturnTime()
435  if (currentPhase.isCommit()) {
436  // decide which chain to activate. Gotta work on this
437  return getPhaseIndexWithMaxCTS();
438  }
439  if (currentPhase.isTransient()) {
440  //If the junction was in a transient step
441  //=> go to the next step and return computeReturnTime()
442  return getCurrentPhaseIndex() + 1;
443  }
444 
445  if (currentPhase.isDecisional()) {
446 
447  if (canRelease()) {
448  return getCurrentPhaseIndex() + 1;
449  }
450  }
451 
452  return getCurrentPhaseIndex();
453 }
454 
455 SUMOTime
457  if (MSNet::getInstance()->getCurrentTimeStep() % 1000 == 0) {
458  WRITE_MESSAGE("MSSOTLTrafficLightLogic::trySwitch()")
459  // To check if decideNextPhase changes the step
460  int previousStep = getCurrentPhaseIndex() ;
461  SUMOTime elapsed = getCurrentPhaseElapsed();
462  // Update CTS according to sensors
463  updateCTS();
464 
465  // Invoking the function member, specialized for each SOTL logic
467  MSPhaseDefinition currentPhase = getCurrentPhaseDef();
468 
469  //At the end, check if new step started
470  if (getCurrentPhaseIndex() != previousStep) {
471  //Check if a new steps chain started
472  if (currentPhase.isTarget()) {
473  //Reset CTS for the ending steps chain
475  //Update lastTargetPhase
477  for (std::map<int, int>::iterator it = targetPhasesLastSelection.begin(); it != targetPhasesLastSelection.end(); ++ it) {
478  if (it->first == lastChain) {
479  if (it->second >= getTargetPhaseMaxLastSelection()) {
480  std::ostringstream oss;
481  oss << "Forced selection of the phase " << lastChain << " since its last selection was " << it->second << " changes ago";
482  WRITE_MESSAGE(oss.str())
483  }
484  it->second = 0;
485  } else if (it->first != previousStep) {
486  ++it->second;
487  }
488  }
490  decayThreshold = 1;
491  }
492  }
493  //Inform the sensors logic
495  //Store the time the new phase started
498  decayThreshold = 1;
499  }
500  ANALYSIS_DBG(
501  std::ostringstream oss;
502  oss << getID() << " from " << getPhase(previousStep).getState() << " to " << currentPhase.getState() << " after " << time2string(elapsed);
503  WRITE_MESSAGE(time2string(MSNet::getInstance()->getCurrentTimeStep()) + "\tMSSOTLTrafficLightLogic::trySwitch " + oss.str());
504  )
505  }
506  }
507  return computeReturnTime();
508 }
509 
511  if (getParameter("USE_PUSH_BUTTON", "0") == "0") {
512  return false;
513  }
514  const MSPhaseDefinition currentPhase = getCurrentPhaseDef();
515  if (m_pushButtons.find(currentPhase.getState()) == m_pushButtons.end()) {
516  m_pushButtons[currentPhase.getState()] = MSPedestrianPushButton::loadPushButtons(&currentPhase);
517  }
518  return MSPushButton::anyActive(m_pushButtons[currentPhase.getState()]);
519 }
520 
#define SENSORS_TYPE
#define SENSORS_TYPE_E1
#define SENSORS_TYPE_E2
#define ANALYSIS_DBG(X)
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:278
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:284
std::string time2string(SUMOTime t)
convert SUMOTime to string
Definition: SUMOTime.cpp:68
long long int SUMOTime
Definition: SUMOTime.h:31
TrafficLightType
T MAX2(T a, T b)
Definition: StdDefs.h:79
#define DBG(X)
Definition: SwarmDebug.h:30
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:44
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:171
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition: MSNet.h:313
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
std::vector< std::string > LaneIdVector
SUMOTime myLastSwitch
Stores the timestep of the last on-switched of the phase.
const LaneIdVector & getTargetLaneSet() const
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 buildSensors(MSTrafficLightLogic::LaneVectorVector controlledLanes, NLDetectorBuilder &nb)
This function member has to be extended to properly build sensors for the input lanes Sensors has to ...
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.
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.
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:124
const std::string & getID() const
Returns the id.
Definition: Named.h:73
const std::string getParameter(const std::string &key, const std::string defaultValue="") const
Returns the value for a given key.
static double rand(std::mt19937 *rng=nullptr)
Returns a random real number in [0, 1)
Definition: RandHelper.h:51
static const T & getRandomFrom(const std::vector< T > &v, std::mt19937 *rng=0)
Returns a random element from the given vector.
Definition: RandHelper.h:147