LCOV - code coverage report
Current view: top level - src/microsim/traffic_lights - MSSimpleTrafficLightLogic.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 131 146 89.7 %
Date: 2024-05-19 15:37:39 Functions: 21 22 95.5 %

          Line data    Source code
       1             : /****************************************************************************/
       2             : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3             : // Copyright (C) 2001-2024 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             : /****************************************************************************/
      14             : /// @file    MSSimpleTrafficLightLogic.cpp
      15             : /// @author  Daniel Krajzewicz
      16             : /// @author  Julia Ringel
      17             : /// @author  Jakob Erdmann
      18             : /// @author  Michael Behrisch
      19             : /// @author  Friedemann Wesner
      20             : /// @date    Sept 2002
      21             : ///
      22             : // A fixed traffic light logic
      23             : /****************************************************************************/
      24             : #include <config.h>
      25             : 
      26             : #include <cassert>
      27             : #include <utility>
      28             : #include <vector>
      29             : #include <bitset>
      30             : #include <sstream>
      31             : #include <utils/common/StringUtils.h>
      32             : #include <microsim/MSEventControl.h>
      33             : #include <microsim/MSNet.h>
      34             : #include <microsim/MSEventControl.h>
      35             : #include "MSTLLogicControl.h"
      36             : #include "MSTrafficLightLogic.h"
      37             : #include "MSSimpleTrafficLightLogic.h"
      38             : 
      39             : //#define DEBUG_COORDINATION
      40             : #define DEBUG_COND (getID()=="C")
      41             : 
      42             : 
      43             : // ===========================================================================
      44             : // member method definitions
      45             : // ===========================================================================
      46      106411 : MSSimpleTrafficLightLogic::MSSimpleTrafficLightLogic(MSTLLogicControl& tlcontrol,
      47             :         const std::string& id, const std::string& programID, const SUMOTime offset, const TrafficLightType logicType, const Phases& phases,
      48             :         int step, SUMOTime delay,
      49      106411 :         const Parameterised::Map& parameters) :
      50             :     MSTrafficLightLogic(tlcontrol, id, programID, offset, logicType, delay, parameters),
      51      106411 :     myPhases(phases),
      52      106411 :     myStep(step) {
      53      106411 :     myDefaultCycleTime = computeCycleTime(myPhases);
      54      106411 :     if (myStep < (int)myPhases.size()) {
      55      106236 :         myPhases[myStep]->myLastSwitch = SIMSTEP;
      56             :     }
      57             :     // the following initializations are only used by 'actuated' and 'delay_based' but do not affect 'static'
      58      212822 :     if (hasParameter(toString(SUMO_ATTR_CYCLETIME))) {
      59           6 :         myDefaultCycleTime = TIME2STEPS(StringUtils::toDouble(Parameterised::getParameter(toString(SUMO_ATTR_CYCLETIME), "")));
      60             :     }
      61      106411 :     myCoordinated = StringUtils::toBool(Parameterised::getParameter("coordinated", "false"));
      62      106411 :     if (myPhases.size() > 0) {
      63      106236 :         SUMOTime earliest = SIMSTEP + getEarliest(-1);
      64      106236 :         if (earliest > getNextSwitchTime()) {
      65          12 :             mySwitchCommand->deschedule(this);
      66          12 :             mySwitchCommand = new SwitchCommand(tlcontrol, this, earliest);
      67          12 :             MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(mySwitchCommand, earliest);
      68             :         }
      69             :     }
      70      106411 : }
      71             : 
      72             : 
      73      211128 : MSSimpleTrafficLightLogic::~MSSimpleTrafficLightLogic() {
      74      106129 :     deletePhases();
      75      211128 : }
      76             : 
      77             : 
      78             : // ------------ Switching and setting current rows
      79             : SUMOTime
      80     8538162 : MSSimpleTrafficLightLogic::trySwitch() {
      81             :     // check whether the current duration shall be increased
      82     8538162 :     if (myCurrentDurationIncrement > 0) {
      83             :         SUMOTime delay = myCurrentDurationIncrement;
      84           0 :         myCurrentDurationIncrement = 0;
      85           0 :         return delay;
      86             :     }
      87             : 
      88             :     // increment the index
      89     8538162 :     if (myPhases[myStep]->nextPhases.size() > 0 && myPhases[myStep]->nextPhases.front() >= 0) {
      90         266 :         myStep = myPhases[myStep]->nextPhases.front();
      91             :     } else {
      92     8537896 :         myStep++;
      93             :     }
      94             :     // if the last phase was reached ...
      95     8538162 :     if (myStep >= (int)myPhases.size()) {
      96             :         // ... set the index to the first phase
      97     3355570 :         myStep = 0;
      98             :     }
      99             :     assert((int)myPhases.size() > myStep);
     100             :     //stores the time the phase started
     101     8538162 :     myPhases[myStep]->myLastSwitch = MSNet::getInstance()->getCurrentTimeStep();
     102             :     // check whether the next duration was overridden
     103     8538162 :     if (myOverridingTimes.size() > 0) {
     104           0 :         SUMOTime nextDuration = myOverridingTimes[0];
     105           0 :         myOverridingTimes.erase(myOverridingTimes.begin());
     106           0 :         return nextDuration;
     107             :     }
     108             :     // return offset to the next switch
     109     8538162 :     return myPhases[myStep]->duration;
     110             : }
     111             : 
     112             : 
     113             : // ------------ Static Information Retrieval
     114             : int
     115        5695 : MSSimpleTrafficLightLogic::getPhaseNumber() const {
     116        5695 :     return (int) myPhases.size();
     117             : }
     118             : 
     119             : 
     120             : const MSSimpleTrafficLightLogic::Phases&
     121      247185 : MSSimpleTrafficLightLogic::getPhases() const {
     122      247185 :     return myPhases;
     123             : }
     124             : 
     125             : 
     126             : MSSimpleTrafficLightLogic::Phases&
     127        3276 : MSSimpleTrafficLightLogic::getPhases() {
     128        3276 :     return myPhases;
     129             : }
     130             : 
     131             : 
     132             : const MSPhaseDefinition&
     133      222071 : MSSimpleTrafficLightLogic::getPhase(int givenStep) const {
     134             :     assert((int)myPhases.size() > givenStep);
     135      222071 :     return *myPhases[givenStep];
     136             : }
     137             : 
     138             : 
     139             : // ------------ Dynamic Information Retrieval
     140             : int
     141    20169822 : MSSimpleTrafficLightLogic::getCurrentPhaseIndex() const {
     142    20169822 :     return myStep;
     143             : }
     144             : 
     145             : 
     146             : const MSPhaseDefinition&
     147    17945026 : MSSimpleTrafficLightLogic::getCurrentPhaseDef() const {
     148    17945026 :     return *myPhases[myStep];
     149             : }
     150             : 
     151             : 
     152             : // ------------ Conversion between time and phase
     153             : SUMOTime
     154           0 : MSSimpleTrafficLightLogic::getPhaseIndexAtTime(SUMOTime simStep) const {
     155             :     SUMOTime position = 0;
     156           0 :     if (myStep > 0) {
     157           0 :         for (int i = 0; i < myStep; i++) {
     158           0 :             position = position + getPhase(i).duration;
     159             :         }
     160             :     }
     161           0 :     position = position + simStep - getPhase(myStep).myLastSwitch;
     162           0 :     position = position % myDefaultCycleTime;
     163             :     assert(position <= myDefaultCycleTime);
     164           0 :     return position;
     165             : }
     166             : 
     167             : 
     168             : SUMOTime
     169         328 : MSSimpleTrafficLightLogic::getOffsetFromIndex(int index) const {
     170             :     assert(index < (int)myPhases.size());
     171         328 :     if (index == 0) {
     172             :         return 0;
     173             :     }
     174             :     SUMOTime pos = 0;
     175         770 :     for (int i = 0; i < index; i++) {
     176         556 :         pos += getPhase(i).duration;
     177             :     }
     178             :     return pos;
     179             : }
     180             : 
     181             : 
     182             : int
     183           8 : MSSimpleTrafficLightLogic::getIndexFromOffset(SUMOTime offset) const {
     184           8 :     offset = offset % myDefaultCycleTime;
     185           8 :     if (offset == myDefaultCycleTime) {
     186             :         return 0;
     187             :     }
     188             :     SUMOTime testPos = 0;
     189           8 :     for (int i = 0; i < (int)myPhases.size(); i++) {
     190           8 :         testPos = testPos + getPhase(i).duration;
     191           8 :         if (testPos > offset) {
     192           8 :             return i;
     193             :         }
     194           0 :         if (testPos == offset) {
     195             :             assert((int)myPhases.size() > (i + 1));
     196           0 :             return (i + 1);
     197             :         }
     198             :     }
     199             :     return 0;
     200             : }
     201             : 
     202             : 
     203             : SUMOTime
     204      145620 : MSSimpleTrafficLightLogic::mapTimeInCycle(SUMOTime t) const {
     205      145620 :     return (myCoordinated
     206      145620 :             ? (t - myOffset) % myDefaultCycleTime
     207       59923 :             : (t - myPhases[0]->myLastSwitch) % myDefaultCycleTime);
     208             : }
     209             : 
     210             : 
     211             : 
     212             : 
     213             : SUMOTime
     214      316623 : MSSimpleTrafficLightLogic::getEarliest(SUMOTime prevStart) const {
     215      316623 :     SUMOTime earliest = getEarliestEnd();
     216      316623 :     if (earliest == MSPhaseDefinition::UNSPECIFIED_DURATION) {
     217             :         return 0;
     218             :     } else {
     219        3460 :         if (prevStart >= SIMSTEP - getTimeInCycle() && prevStart < getCurrentPhaseDef().myLastEnd) {
     220             :             // phase was started and ended once already in the current cycle
     221             :             // it should not end a second time in the same cycle
     222         167 :             earliest += myDefaultCycleTime;
     223             : #ifdef DEBUG_COORDINATION
     224             :             if (DEBUG_COND) {
     225             :                 std::cout << SIMTIME << " tl=" << getID() << " getEarliest phase=" << myStep
     226             :                           << " prevStart= " << STEPS2TIME(prevStart)
     227             :                           << " prevEnd= " << STEPS2TIME(getCurrentPhaseDef().myLastEnd)
     228             :                           << " cycleStart=" << STEPS2TIME(SIMSTEP - getTimeInCycle()) << " started Twice - move into next cycle\n";
     229             :             }
     230             : #endif
     231             :         } else {
     232        3293 :             SUMOTime latest = getLatestEnd();
     233        3293 :             if (latest != MSPhaseDefinition::UNSPECIFIED_DURATION) {
     234        2246 :                 const SUMOTime minRemaining = getMinDur() - (SIMSTEP - getCurrentPhaseDef().myLastSwitch);
     235        2246 :                 const SUMOTime minEnd = getTimeInCycle() + minRemaining;
     236        2246 :                 if (latest > earliest && latest < minEnd) {
     237             :                     // cannot terminate phase between earliest and latest -> move end into next cycle
     238          82 :                     earliest += myDefaultCycleTime;
     239        2164 :                 } else if (latest < earliest && latest >= minEnd) {
     240             :                     // can ignore earliest since it counts from the previous cycle
     241         144 :                     earliest -= myDefaultCycleTime;
     242             :                 }
     243             : #ifdef DEBUG_COORDINATION
     244             :                 if (DEBUG_COND) {
     245             :                     std::cout << SIMTIME << " tl=" << getID() << " getEarliest phase=" << myStep << " latest=" << STEPS2TIME(latest) << " minEnd="
     246             :                               << STEPS2TIME(minEnd) << " earliest=" << STEPS2TIME(earliest) << "\n";
     247             :                 }
     248             : #endif
     249             :             }
     250             :         }
     251        3460 :         const SUMOTime maxRemaining = getMaxDur() - (SIMSTEP - getCurrentPhaseDef().myLastSwitch);
     252        3460 :         return MIN2(earliest - getTimeInCycle(), maxRemaining);
     253             :     }
     254             : }
     255             : 
     256             : 
     257             : SUMOTime
     258     1250406 : MSSimpleTrafficLightLogic::getLatest() const {
     259     1250406 :     const SUMOTime latest = getLatestEnd();
     260     1250406 :     if (latest == MSPhaseDefinition::UNSPECIFIED_DURATION) {
     261             :         return SUMOTime_MAX; // no restriction
     262             :     } else {
     263      125203 :         if (latest < getEarliestEnd()) {
     264       10828 :             const SUMOTime running = SIMSTEP - getCurrentPhaseDef().myLastSwitch;
     265       10828 :             if (running < getTimeInCycle()) {
     266             :                 // phase was started in the current cycle so the restriction does not apply yet
     267             :                 return SUMOTime_MAX;
     268             :             }
     269             :         }
     270             : #ifdef DEBUG_COORDINATION
     271             :         if (DEBUG_COND) {
     272             :             std::cout << SIMTIME << " tl=" << getID() << " getLatest phase=" << myStep << " latest=" << STEPS2TIME(latest)
     273             :                       << " cycTime=" << STEPS2TIME(getTimeInCycle()) << " res=" << STEPS2TIME(latest - getTimeInCycle()) << "\n";
     274             :         }
     275             : #endif
     276      117264 :         if (latest == myDefaultCycleTime && getTimeInCycle() == 0) {
     277             :             // special case: end on cylce time wrap-around
     278             :             return 0;
     279             :         }
     280      117252 :         return MAX2(SUMOTime(0), latest - getTimeInCycle());
     281             :     }
     282             : }
     283             : 
     284             : 
     285             : 
     286             : // ------------ Changing phases and phase durations
     287             : void
     288        5480 : MSSimpleTrafficLightLogic::changeStepAndDuration(MSTLLogicControl& tlcontrol,
     289             :         SUMOTime simStep, int step, SUMOTime stepDuration) {
     290        5480 :     mySwitchCommand->deschedule(this);
     291        5480 :     mySwitchCommand = new SwitchCommand(tlcontrol, this, stepDuration + simStep);
     292        5480 :     if (step >= 0 && step != myStep) {
     293        1455 :         myStep = step;
     294        1455 :         myPhases[myStep]->myLastSwitch = MSNet::getInstance()->getCurrentTimeStep();
     295        1455 :         setTrafficLightSignals(simStep);
     296        1455 :         tlcontrol.get(getID()).executeOnSwitchActions();
     297             :     }
     298        5480 :     MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
     299        5480 :         mySwitchCommand, stepDuration + simStep);
     300        5480 : }
     301             : 
     302             : 
     303             : void
     304          22 : MSSimpleTrafficLightLogic::setPhases(const Phases& phases, int step) {
     305             :     assert(step < (int)phases.size());
     306          22 :     deletePhases();
     307          22 :     myPhases = phases;
     308          22 :     myStep = step;
     309          22 :     myDefaultCycleTime = computeCycleTime(myPhases);
     310          22 : }
     311             : 
     312             : 
     313             : void
     314      106151 : MSSimpleTrafficLightLogic::deletePhases() {
     315      659445 :     for (int i = 0; i < (int)myPhases.size(); i++) {
     316      553294 :         delete myPhases[i];
     317             :     }
     318      106151 : }
     319             : 
     320             : void
     321        1951 : MSSimpleTrafficLightLogic::saveState(OutputDevice& out) const {
     322        1951 :     out.openTag(SUMO_TAG_TLLOGIC);
     323             :     out.writeAttr(SUMO_ATTR_ID, getID());
     324             :     out.writeAttr(SUMO_ATTR_PROGRAMID, getProgramID());
     325        1951 :     out.writeAttr(SUMO_ATTR_PHASE, getCurrentPhaseIndex());
     326        1951 :     out.writeAttr(SUMO_ATTR_DURATION, getSpentDuration());
     327        1951 :     out.closeTag();
     328        1951 : }
     329             : 
     330             : const std::string
     331     2233231 : MSSimpleTrafficLightLogic::getParameter(const std::string& key, const std::string defaultValue) const {
     332     2233231 :     if (key == "cycleTime") {
     333          12 :         return toString(STEPS2TIME(myDefaultCycleTime));
     334     2233219 :     } else if (key == "offset") {
     335          12 :         return toString(STEPS2TIME(myOffset));
     336     2233207 :     } else if (key == "coordinated") {
     337          12 :         return toString(myCoordinated);
     338     2233195 :     } else if (key == "cycleSecond") {
     339          12 :         return toString(STEPS2TIME(getTimeInCycle()));
     340     2233183 :     } else if (key == "typeName") {
     341           6 :         return toString(this->getLogicType());
     342             :     }
     343     4466354 :     return Parameterised::getParameter(key, defaultValue);
     344             : }
     345             : 
     346             : void
     347          89 : MSSimpleTrafficLightLogic::setParameter(const std::string& key, const std::string& value) {
     348          89 :     if (key == "cycleTime") {
     349           6 :         myDefaultCycleTime = string2time(value);
     350           6 :         Parameterised::setParameter(key, value);
     351         166 :     } else if (key == "cycleSecond" || key == "typeName") {
     352           0 :         throw InvalidArgument(key + " cannot be changed dynamically for traffic light '" + getID() + "'");
     353          83 :     } else if (key == "offset") {
     354           6 :         myOffset = string2time(value);
     355          77 :     } else if (key == "coordinated") {
     356           6 :         myCoordinated = StringUtils::toBool(value);
     357           6 :         Parameterised::setParameter(key, value);
     358             :     } else {
     359          71 :         Parameterised::setParameter(key, value);
     360             :     }
     361          89 : }
     362             : 
     363             : /****************************************************************************/

Generated by: LCOV version 1.14