1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2013-2019 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials
5 // are made available under the terms of the Eclipse Public License v2.0
6 // which accompanies this distribution, and is available at
7 // http://www.eclipse.org/legal/epl-v20.html
8 // SPDX-License-Identifier: EPL-2.0
9 /****************************************************************************/
10 /// @file MSSOTLTrafficLightLogic.cpp
11 /// @author Gianfilippo Slager
12 /// @author Anna Chiara Bellini
13 /// @author Federico Caselli
14 /// @date Apr 2013
15 /// @version $Id$
16 ///
17 // The base abstract class for SOTL logics
18 /****************************************************************************/
19
20 #include "MSSOTLTrafficLightLogic.h"
21 #include "../MSLane.h"
22 #include "../MSEdge.h"
23 #include "MSPushButton.h"
24
25 #if 1
26 #define ANALYSIS_DBG(X) {X}
27 #else
28 #define ANALYSIS_DBG(X) DBG(X)
29 #endif
30 // ===========================================================================
31 // member method definitions
32 // ===========================================================================
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)33 MSSOTLTrafficLightLogic::MSSOTLTrafficLightLogic(
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, logicType, phases, step, delay, parameters) {
43 this->mySensors = nullptr;
44 this->myCountSensors = nullptr;
45 sensorsSelfBuilt = true;
46 checkPhases();
47 setupCTS();
48 setToATargetPhase();
49 }
50
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,MSSOTLSensors * sensors)51 MSSOTLTrafficLightLogic::MSSOTLTrafficLightLogic(
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, logicType, phases, step, delay, parameters) {
62 this->mySensors = sensors;
63 sensorsSelfBuilt = false;
64 checkPhases();
65 setupCTS();
66 setToATargetPhase();
67 }
68
~MSSOTLTrafficLightLogic()69 MSSOTLTrafficLightLogic::~MSSOTLTrafficLightLogic() {
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
logStatus()84 void MSSOTLTrafficLightLogic::logStatus() {
85
86 }
87
88 void
checkPhases()89 MSSOTLTrafficLightLogic::checkPhases() {
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
setupCTS()98 MSSOTLTrafficLightLogic::setupCTS() {
99 for (int phaseStep = 0; phaseStep < (int)getPhases().size(); phaseStep++) {
100 if (getPhase(phaseStep).isTarget()) {
101 targetPhasesCTS[phaseStep] = 0;
102 lastCheckForTargetPhase[phaseStep] = MSNet::getInstance()->getCurrentTimeStep();
103 targetPhasesLastSelection[phaseStep] = 0;
104 }
105 }
106 }
107
108 void
setToATargetPhase()109 MSSOTLTrafficLightLogic::setToATargetPhase() {
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
init(NLDetectorBuilder & nb)122 MSSOTLTrafficLightLogic::init(NLDetectorBuilder& nb) {
123
124 MSTrafficLightLogic::init(nb);
125
126 if (isDecayThresholdActivated()) {
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
138 LaneVectorVector lvv = getLaneVectors();
139
140 DBG(
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 )
152
153 mySensors = new MSSOTLE2Sensors(myID, &(getPhases()));
154 ((MSSOTLE2Sensors*)mySensors)->buildSensors(myLanes, nb, getInputSensorsLength());
155 mySensors->stepChanged(getCurrentPhaseIndex());
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()));
164 myCountSensors->buildCountSensors(myLanes, nb);
165 myCountSensors->stepChanged(getCurrentPhaseIndex());
166
167 //Adding Sensors to the outgoing Lanes
168
169 LinkVectorVector myLinks = getLinks();
170
171
172 DBG(
173 WRITE_MESSAGE("Listing output lanes");
174 for (int i = 0; i < myLinks.size(); i++) {
175 LinkVector oneLink = getLinksAt(i);
176
177 for (int j = 0; j < oneLink.size(); j++) {
178
179 MSLane* lane = oneLink[j]->getLane();
180 WRITE_MESSAGE(lane ->getID());
181
182 }
183 }
184 )
185
186
187 LaneVectorVector myLaneVector;
188
189 LaneVector outLanes;
190 LinkVectorVector myoutLinks = getLinks();
191
192 for (int i = 0; i < (int)myLinks.size(); i++) {
193 LinkVector oneLink = getLinksAt(i);
194 for (int j = 0; j < (int)oneLink.size(); j++) {
195 MSLane* lane = oneLink[j]->getLane();
196 outLanes.push_back(lane);
197 }
198 }
199
200 if (outLanes.size() > 0) {
201 myLaneVector.push_back(outLanes);
202 }
203 if (myLaneVector.size() > 0) {
204 ((MSSOTLE2Sensors*)mySensors)->buildOutSensors(myLaneVector, nb, getOutputSensorsLength());
205 myCountSensors->buildCountOutSensors(myLaneVector, nb);
206 }
207
208 }
209 }
210 }
211
212
213 void
resetCTS(int phaseStep)214 MSSOTLTrafficLightLogic::resetCTS(int phaseStep) {
215 std::map<int, SUMOTime>::iterator phaseIterator = targetPhasesCTS.find(phaseStep);
216 if (phaseIterator != targetPhasesCTS.end()) {
217 phaseIterator->second = 0;
218 lastCheckForTargetPhase[phaseStep] = MSNet::getInstance()->getCurrentTimeStep();
219 }
220 }
221
222 void
updateCTS()223 MSSOTLTrafficLightLogic::updateCTS() {
224 SUMOTime elapsedTimeSteps = 0;
225 SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
226 //Iterate over the target phase map and update CTS value for every target phase except for the one belonging to the current steps chain
227 for (std::map<int, SUMOTime>::iterator mapIterator = targetPhasesCTS.begin();
228 mapIterator != targetPhasesCTS.end();
229 mapIterator++) {
230 int chain = mapIterator->first;
231 SUMOTime oldVal = mapIterator->second;
232 if (chain != lastChain) {
233 //Get the number of timesteps since the last check for that phase
234 elapsedTimeSteps = now - lastCheckForTargetPhase[chain];
235 //Update the last check time
236 lastCheckForTargetPhase[chain] = now;
237 //Increment the CTS
238 //SWITCH between 3 counting vehicles function
239 switch (getMode()) {
240 case (0):
241 mapIterator->second += elapsedTimeSteps
242 * countVehicles(getPhase(chain)); //SUMO
243 break;
244 case (1):
245 mapIterator->second += elapsedTimeSteps
246 * countVehicles(getPhase(chain)); //COMPLEX
247 break;
248 case (2):
249 mapIterator->second = countVehicles(getPhase(chain)); //QUEUE
250 break;
251 default:
252 WRITE_ERROR("Unrecognized traffic threshold calculation mode");
253 }
254 std::ostringstream oss;
255 oss << "MSSOTLTrafficLightLogic::updateCTS->TLC " << getID() << " chain " << chain << " oldVal " << oldVal << " newVal " << mapIterator->second;
256 WRITE_MESSAGE(oss.str());
257 }
258 if (isDecayThresholdActivated()) {
259 updateDecayThreshold();
260 }
261 }
262 }
263
264 int
countVehicles(MSPhaseDefinition phase)265 MSSOTLTrafficLightLogic::countVehicles(MSPhaseDefinition phase) {
266
267 if (!phase.isTarget()) {
268 return 0;
269 }
270
271 int accumulator = 0;
272 //Iterate over the target lanes for the current target phase to get the number of approaching vehicles
273 MSPhaseDefinition::LaneIdVector targetLanes = phase.getTargetLaneSet();
274 for (MSPhaseDefinition::LaneIdVector::const_iterator laneIterator = targetLanes.begin(); laneIterator != targetLanes.end(); laneIterator++) {
275 //SWITCH between 3 counting vehicles function
276 switch (getMode()) {
277 case (0):
278 accumulator += mySensors->countVehicles((*laneIterator)); //SUMO
279 break;
280 case (1):
281 accumulator += ((MSSOTLE2Sensors*)mySensors)->estimateVehicles((*laneIterator)); //COMPLEX
282 break;
283 case (2):
284 accumulator = MAX2((int)((MSSOTLE2Sensors*)mySensors)->getEstimateQueueLength((*laneIterator)), accumulator); //QUEUE
285 break;
286 default:
287 WRITE_ERROR("Unrecognized traffic threshold calculation mode");
288 }
289 }
290 return accumulator;
291 }
292
293 void
updateDecayThreshold()294 MSSOTLTrafficLightLogic::updateDecayThreshold() {
295 if (getCurrentPhaseDef().isGreenPhase()) {
296 decayThreshold = decayThreshold * exp(getDecayConstant());
297 }
298 // ANALYSIS_DBG(
299 DBG(
300 std::stringstream out;
301 out << decayThreshold;
302 WRITE_MESSAGE("\n" + time2string(MSNet::getInstance()->getCurrentTimeStep()) + "\tMSSOTLTrafficLightLogic::updateDecayThreshold():: " + out.str());
303 )
304 }
305 bool
isThresholdPassed()306 MSSOTLTrafficLightLogic::isThresholdPassed() {
307
308 DBG(
309 // WRITE_MESSAGE("\n" +time2string(MSNet::getInstance()->getCurrentTimeStep()) +"\tMSSOTLTrafficLightLogic::isThresholdPassed():: " + " tlsid=" + getID());
310
311 std::ostringstream threshold_str;
312 // threshold_str << "tlsid=" << getID() << " targetPhaseCTS size=" << targetPhasesCTS.size();
313 // threshold_str << "\n";
314 WRITE_MESSAGE(threshold_str.str());
315 )
316 /*
317 * if a dynamic threshold based on the exponential decrease, if passed we force the phase change
318 */
319 // double random = ((double) RandHelper::rand(RAND_MAX) / (RAND_MAX));
320 double random = RandHelper::rand();
321 // ANALYSIS_DBG(
322 DBG(
323 if (isDecayThresholdActivated()) {
324 std::ostringstream str;
325 str << time2string(MSNet::getInstance()->getCurrentTimeStep()) << "\tMSSOTLTrafficLightLogic::isThresholdPassed():: "
326 << " tlsid=" << getID() << " decayThreshold=" << decayThreshold << " random=" << random << ">" << (1 - decayThreshold)
327 << (random > (1 - decayThreshold) ? " true" : " false");
328
329 WRITE_MESSAGE(str.str());
330 }
331 )
332 if (!isDecayThresholdActivated() || (isDecayThresholdActivated() && random > (1 - decayThreshold))) {
333 for (std::map<int, SUMOTime>::const_iterator iterator =
334 targetPhasesCTS.begin(); iterator != targetPhasesCTS.end();
335 iterator++) {
336 DBG(
337 SUMOTime step = MSNet::getInstance()->getCurrentTimeStep();
338 std::ostringstream threshold_str;
339 // threshold_str <<"\tTL " +getID()<<" time " +time2string(step)<< "(getThreshold()= " << getThreshold()
340 // << ", targetPhaseCTS= " << iterator->second << " )" << " phase="<<getPhase(iterator->first).getState();
341 threshold_str << getCurrentPhaseDef().getState() << ";" << time2string(step) << ";" << getThreshold()
342 << ";" << iterator->second << ";" << getPhase(iterator->first).getState() << ";"
343 << iterator->first << "!=" << lastChain;
344 WRITE_MESSAGE(threshold_str.str());
345 );
346 //Note that the current chain is not eligible to be directly targeted again, it would be unfair
347 if ((iterator->first != lastChain) && (getThreshold() <= iterator->second)) {
348 return true;
349 }
350 }
351 return false;
352 } else {
353 return true;
354 }
355 }
356
357
358 SUMOTime
getCurrentPhaseElapsed()359 MSSOTLTrafficLightLogic::getCurrentPhaseElapsed() {
360 MSPhaseDefinition currentPhase = getCurrentPhaseDef();
361
362 SUMOTime now = MSNet::getInstance()->getCurrentTimeStep();
363 SUMOTime elapsed = now - currentPhase.myLastSwitch;
364
365 return elapsed;
366 }
367
368
369 int
getPhaseIndexWithMaxCTS()370 MSSOTLTrafficLightLogic::getPhaseIndexWithMaxCTS() {
371 SUMOTime maxCTS = 0;
372 int maxLastStep = getTargetPhaseMaxLastSelection();
373 bool usedMaxCTS = false;
374 std::vector<int> equalIndexes;
375 for (std::map<int, int>::const_iterator it = targetPhasesLastSelection.begin();
376 it != targetPhasesLastSelection.end(); ++it) {
377 if (it->first != lastChain) {
378 if (maxLastStep < it->second) {
379 maxLastStep = it->second;
380 equalIndexes.clear();
381 equalIndexes.push_back(it->first);
382 } else if (maxLastStep == it->second) {
383 equalIndexes.push_back(it->first);
384 }
385 }
386 }
387 if (equalIndexes.size() == 0) {
388 usedMaxCTS = true;
389 for (std::map<int, SUMOTime>::const_iterator iterator = targetPhasesCTS.begin();
390 iterator != targetPhasesCTS.end(); ++iterator) {
391 if (iterator->first != lastChain) {
392 if (maxCTS < iterator->second) {
393 maxCTS = iterator->second;
394 equalIndexes.clear();
395 equalIndexes.push_back(iterator->first);
396 } else if (maxCTS == iterator->second) {
397 equalIndexes.push_back(iterator->first);
398 }
399 }
400 }
401 }
402
403 std::ostringstream oss;
404 oss << "MSSOTLTrafficLightLogic::getPhaseIndexWithMaxCTS-> TLC " << getID();
405 if (usedMaxCTS) {
406 oss << " maxCTS " << maxCTS;
407 } else {
408 oss << " forcing selection since not selected for " << maxLastStep;
409 }
410 if (equalIndexes.size() == 1) {
411 oss << " phase " << equalIndexes[0];
412 WRITE_MESSAGE(oss.str());
413 return equalIndexes[0];
414 } else {
415 const int index = RandHelper::getRandomFrom(equalIndexes);
416 oss << " phases [";
417 for (std::vector<int>::const_iterator it = equalIndexes.begin(); it != equalIndexes.end(); ++it) {
418 oss << *it << ", ";
419 }
420 oss << "]. Random select " << index;
421 WRITE_MESSAGE(oss.str());
422 return index;
423 }
424 }
425
426 int
decideNextPhase()427 MSSOTLTrafficLightLogic::decideNextPhase() {
428 MSPhaseDefinition currentPhase = getCurrentPhaseDef();
429 //If the junction was in a commit step
430 //=> go to the target step that gives green to the set with the current highest CTS
431 // and return computeReturnTime()
432 if (currentPhase.isCommit()) {
433 // decide which chain to activate. Gotta work on this
434 return getPhaseIndexWithMaxCTS();
435 }
436 if (currentPhase.isTransient()) {
437 //If the junction was in a transient step
438 //=> go to the next step and return computeReturnTime()
439 return getCurrentPhaseIndex() + 1;
440 }
441
442 if (currentPhase.isDecisional()) {
443
444 if (canRelease()) {
445 return getCurrentPhaseIndex() + 1;
446 }
447 }
448
449 return getCurrentPhaseIndex();
450 }
451
452 SUMOTime
trySwitch()453 MSSOTLTrafficLightLogic::trySwitch() {
454 if (MSNet::getInstance()->getCurrentTimeStep() % 1000 == 0) {
455 WRITE_MESSAGE("MSSOTLTrafficLightLogic::trySwitch()")
456 // To check if decideNextPhase changes the step
457 int previousStep = getCurrentPhaseIndex() ;
458 SUMOTime elapsed = getCurrentPhaseElapsed();
459 // Update CTS according to sensors
460 updateCTS();
461
462 // Invoking the function member, specialized for each SOTL logic
463 setStep(decideNextPhase());
464 MSPhaseDefinition currentPhase = getCurrentPhaseDef();
465
466 //At the end, check if new step started
467 if (getCurrentPhaseIndex() != previousStep) {
468 //Check if a new steps chain started
469 if (currentPhase.isTarget()) {
470 //Reset CTS for the ending steps chain
471 resetCTS(lastChain);
472 //Update lastTargetPhase
473 lastChain = getCurrentPhaseIndex();
474 for (std::map<int, int>::iterator it = targetPhasesLastSelection.begin(); it != targetPhasesLastSelection.end(); ++ it) {
475 if (it->first == lastChain) {
476 if (it->second >= getTargetPhaseMaxLastSelection()) {
477 std::ostringstream oss;
478 oss << "Forced selection of the phase " << lastChain << " since its last selection was " << it->second << " changes ago";
479 WRITE_MESSAGE(oss.str())
480 }
481 it->second = 0;
482 } else if (it->first != previousStep) {
483 ++it->second;
484 }
485 }
486 if (isDecayThresholdActivated()) {
487 decayThreshold = 1;
488 }
489 }
490 //Inform the sensors logic
491 mySensors->stepChanged(getCurrentPhaseIndex());
492 //Store the time the new phase started
493 currentPhase.myLastSwitch = MSNet::getInstance()->getCurrentTimeStep();
494 if (isDecayThresholdActivated()) {
495 decayThreshold = 1;
496 }
497 ANALYSIS_DBG(
498 std::ostringstream oss;
499 oss << getID() << " from " << getPhase(previousStep).getState() << " to " << currentPhase.getState() << " after " << time2string(elapsed);
500 WRITE_MESSAGE(time2string(MSNet::getInstance()->getCurrentTimeStep()) + "\tMSSOTLTrafficLightLogic::trySwitch " + oss.str());
501 )
502 }
503 }
504 return computeReturnTime();
505 }
506
isPushButtonPressed()507 bool MSSOTLTrafficLightLogic::isPushButtonPressed() {
508 if (getParameter("USE_PUSH_BUTTON", "0") == "0") {
509 return false;
510 }
511 const MSPhaseDefinition currentPhase = getCurrentPhaseDef();
512 if (m_pushButtons.find(currentPhase.getState()) == m_pushButtons.end()) {
513 m_pushButtons[currentPhase.getState()] = MSPedestrianPushButton::loadPushButtons(¤tPhase);
514 }
515 return MSPushButton::anyActive(m_pushButtons[currentPhase.getState()]);
516 }
517
518