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(&currentPhase);
514     }
515     return MSPushButton::anyActive(m_pushButtons[currentPhase.getState()]);
516 }
517 
518