Eclipse SUMO - Simulation of Urban MObility
Loading...
Searching...
No Matches
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-2025 German Aerospace Center (DLR) and others.
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// https://www.eclipse.org/legal/epl-2.0/
7// This Source Code may also be made available under the following Secondary
8// Licenses when the conditions for such availability set forth in the Eclipse
9// Public License 2.0 are satisfied: GNU General Public License, version 2
10// or later which is available at
11// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13/****************************************************************************/
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;
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;
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
84
85void
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
94void
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
105void
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
118void
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());
152 mySensors->stepChanged(getCurrentPhaseIndex());
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()));
161 myCountSensors->buildCountSensors(myLanes, nb);
162 myCountSensors->stepChanged(getCurrentPhaseIndex());
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
204void
206 std::map<int, SUMOTime>::iterator phaseIterator = targetPhasesCTS.find(phaseStep);
207 if (phaseIterator != targetPhasesCTS.end()) {
208 phaseIterator->second = 0;
210 }
211}
212
213void
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
255int
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
283void
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}
294bool
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
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
348 MSPhaseDefinition currentPhase = getCurrentPhaseDef();
349
351 SUMOTime elapsed = now - currentPhase.myLastSwitch;
352
353 return elapsed;
354}
355
356
357int
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
414int
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
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
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
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
481 mySensors->stepChanged(getCurrentPhaseIndex());
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:36
#define SENSORS_TYPE
#define SENSORS_TYPE_E1
#define SENSORS_TYPE_E2
#define WRITE_MESSAGE(msg)
Definition MsgHandler.h:288
#define WRITE_ERROR(msg)
Definition MsgHandler.h:295
#define TL(string)
Definition MsgHandler.h:304
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:91
T MAX2(T a, T b)
Definition StdDefs.h:86
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:186
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:334
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.
SUMOTime myLastSwitch
Stores the timestep of the last on-switched of the phase.
const std::string & getState() const
Returns the state within this phase.
bool isDecisional() const
const std::vector< std::string > & getTargetLaneSet() const
static bool anyActive(const std::vector< MSPushButton * > &)
Checks if any pushbutton in the vector is active.
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
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...
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.
MSSimpleTrafficLightLogic(MSTLLogicControl &tlcontrol, const std::string &id, const std::string &programID, const SUMOTime offset, const TrafficLightType logicType, const Phases &phases, int step, SUMOTime delay, const Parameterised::Map &parameters)
Constructor.
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 LinkVectorVector & getLinks() const
Returns the list of lists of all affected links.
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.
LaneVectorVector myLanes
The list of LaneVectors; each vector contains the incoming lanes that belong to the same link index.
const LaneVectorVector & getLaneVectors() const
Returns the list of lists of all lanes controlled by this tls.
std::vector< MSPhaseDefinition * > Phases
Definition of a list of phases, being the junction logic.
const LinkVector & getLinksAt(int i) const
Returns the list of links that are controlled by the signals at the given position.
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.
virtual void inform(std::string msg, bool addType=true)
adds a new error to the list
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
static double rand(SumoRNG *rng=nullptr)
Returns a random real number in [0, 1).
static const T & getRandomFrom(const std::vector< T > &v, SumoRNG *rng=nullptr)
Returns a random element from the given vector.
Definition RandHelper.h:208