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-2023 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());
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
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
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:272
#define WRITE_ERROR(msg)
Definition MsgHandler.h:279
#define TL(string)
Definition MsgHandler.h:287
std::string time2string(SUMOTime t, bool humanReadable)
convert SUMOTime to string (independently of global format setting)
Definition SUMOTime.cpp:69
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:183
SUMOTime getCurrentTimeStep() const
Returns the current simulation step.
Definition MSNet.h:322
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.
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
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 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:204