LCOV - code coverage report
Current view: top level - src/microsim/traffic_lights - MSSimpleTrafficLightLogic.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 90.3 % 155 140
Test Date: 2026-03-02 16:00:03 Functions: 95.7 % 23 22

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 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       116752 : 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       116752 :         const Parameterised::Map& parameters) :
      50              :     MSTrafficLightLogic(tlcontrol, id, programID, offset, logicType, delay, parameters),
      51       116752 :     myPhases(phases),
      52       116752 :     myStep(step) {
      53       116752 :     myDefaultCycleTime = computeCycleTime(myPhases);
      54       116752 :     if (myStep < (int)myPhases.size()) {
      55       116613 :         myPhases[myStep]->myLastSwitch = SIMSTEP;
      56              :     }
      57              :     // the following initializations are only used by 'actuated' and 'delay_based' but do not affect 'static'
      58       233504 :     if (hasParameter(toString(SUMO_ATTR_CYCLETIME))) {
      59           36 :         myDefaultCycleTime = TIME2STEPS(StringUtils::toDouble(Parameterised::getParameter(toString(SUMO_ATTR_CYCLETIME), "")));
      60              :     }
      61       233504 :     myCoordinated = StringUtils::toBool(Parameterised::getParameter("coordinated", "false"));
      62       116752 :     if (myPhases.size() > 0) {
      63       116613 :         SUMOTime earliest = SIMSTEP + getEarliest(-1);
      64       116613 :         if (earliest > getNextSwitchTime()) {
      65           55 :             mySwitchCommand->deschedule(this);
      66           55 :             mySwitchCommand = new SwitchCommand(tlcontrol, this, earliest);
      67           55 :             MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(mySwitchCommand, earliest);
      68              :         }
      69              :     }
      70       116752 : }
      71              : 
      72              : 
      73       231915 : MSSimpleTrafficLightLogic::~MSSimpleTrafficLightLogic() {
      74       116541 :     deletePhases();
      75       231915 : }
      76              : 
      77              : 
      78              : // ------------ Switching and setting current rows
      79              : SUMOTime
      80      4457888 : MSSimpleTrafficLightLogic::trySwitch() {
      81              :     // check whether the current duration shall be increased
      82      4457888 :     if (myCurrentDurationIncrement > 0) {
      83              :         SUMOTime delay = myCurrentDurationIncrement;
      84            0 :         myCurrentDurationIncrement = 0;
      85            0 :         return delay;
      86              :     }
      87              : 
      88              :     // increment the index
      89      4457888 :     if (myPhases[myStep]->nextPhases.size() > 0 && myPhases[myStep]->nextPhases.front() >= 0) {
      90          431 :         myStep = myPhases[myStep]->nextPhases.front();
      91              :     } else {
      92      4457457 :         myStep++;
      93              :     }
      94              :     // if the last phase was reached ...
      95      4457888 :     if (myStep >= (int)myPhases.size()) {
      96              :         // ... set the index to the first phase
      97      1708035 :         myStep = 0;
      98              :     }
      99              :     assert((int)myPhases.size() > myStep);
     100              :     //stores the time the phase started
     101      4457888 :     myPhases[myStep]->myLastSwitch = MSNet::getInstance()->getCurrentTimeStep();
     102              :     // check whether the next duration was overridden
     103      4457888 :     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      4457888 :     return myPhases[myStep]->duration;
     110              : }
     111              : 
     112              : 
     113              : // ------------ Static Information Retrieval
     114              : int
     115         6751 : MSSimpleTrafficLightLogic::getPhaseNumber() const {
     116         6751 :     return (int) myPhases.size();
     117              : }
     118              : 
     119              : 
     120              : const MSSimpleTrafficLightLogic::Phases&
     121       254506 : MSSimpleTrafficLightLogic::getPhases() const {
     122       254506 :     return myPhases;
     123              : }
     124              : 
     125              : 
     126              : MSSimpleTrafficLightLogic::Phases&
     127         1642 : MSSimpleTrafficLightLogic::getPhases() {
     128         1642 :     return myPhases;
     129              : }
     130              : 
     131              : 
     132              : const MSPhaseDefinition&
     133       114488 : MSSimpleTrafficLightLogic::getPhase(int givenStep) const {
     134              :     assert((int)myPhases.size() > givenStep);
     135       114488 :     return *myPhases[givenStep];
     136              : }
     137              : 
     138              : 
     139              : // ------------ Dynamic Information Retrieval
     140              : int
     141     12278206 : MSSimpleTrafficLightLogic::getCurrentPhaseIndex() const {
     142     12278206 :     return myStep;
     143              : }
     144              : 
     145              : 
     146              : const MSPhaseDefinition&
     147     15240310 : MSSimpleTrafficLightLogic::getCurrentPhaseDef() const {
     148     15240310 :     return *myPhases[myStep];
     149              : }
     150              : 
     151              : 
     152              : void
     153          267 : MSSimpleTrafficLightLogic::resetLastSwitch(SUMOTime t) {
     154          267 :     myPhases[myStep]->myLastSwitch = t;
     155          267 : }
     156              : 
     157              : 
     158              : // ------------ Conversion between time and phase
     159              : SUMOTime
     160            0 : MSSimpleTrafficLightLogic::getPhaseIndexAtTime(SUMOTime simStep) const {
     161              :     SUMOTime position = 0;
     162            0 :     if (myStep > 0) {
     163            0 :         for (int i = 0; i < myStep; i++) {
     164            0 :             position = position + getPhase(i).duration;
     165              :         }
     166              :     }
     167            0 :     position = position + simStep - getPhase(myStep).myLastSwitch;
     168            0 :     position = position % myDefaultCycleTime;
     169              :     assert(position <= myDefaultCycleTime);
     170            0 :     return position;
     171              : }
     172              : 
     173              : 
     174              : SUMOTime
     175          656 : MSSimpleTrafficLightLogic::getOffsetFromIndex(int index) const {
     176              :     assert(index < (int)myPhases.size());
     177          656 :     if (index == 0) {
     178              :         return 0;
     179              :     }
     180              :     SUMOTime pos = 0;
     181         1540 :     for (int i = 0; i < index; i++) {
     182         1112 :         pos += getPhase(i).duration;
     183              :     }
     184              :     return pos;
     185              : }
     186              : 
     187              : 
     188              : int
     189           16 : MSSimpleTrafficLightLogic::getIndexFromOffset(SUMOTime offset) const {
     190           16 :     offset = offset % myDefaultCycleTime;
     191           16 :     if (offset == myDefaultCycleTime) {
     192              :         return 0;
     193              :     }
     194              :     SUMOTime testPos = 0;
     195           16 :     for (int i = 0; i < (int)myPhases.size(); i++) {
     196           16 :         testPos = testPos + getPhase(i).duration;
     197           16 :         if (testPos > offset) {
     198           16 :             return i;
     199              :         }
     200            0 :         if (testPos == offset) {
     201              :             assert((int)myPhases.size() > (i + 1));
     202            0 :             return (i + 1);
     203              :         }
     204              :     }
     205              :     return 0;
     206              : }
     207              : 
     208              : 
     209              : SUMOTime
     210       291224 : MSSimpleTrafficLightLogic::mapTimeInCycle(SUMOTime t) const {
     211       291224 :     return (myCoordinated
     212       291224 :             ? (t - myOffset) % myDefaultCycleTime
     213       119837 :             : (t - myPhases[0]->myLastSwitch) % myDefaultCycleTime);
     214              : }
     215              : 
     216              : 
     217              : 
     218              : 
     219              : SUMOTime
     220       385545 : MSSimpleTrafficLightLogic::getEarliest(SUMOTime prevStart) const {
     221       385545 :     SUMOTime earliest = getEarliestEnd();
     222       385545 :     if (earliest == MSPhaseDefinition::UNSPECIFIED_DURATION) {
     223              :         return 0;
     224              :     } else {
     225         6908 :         if (prevStart >= SIMSTEP - getTimeInCycle() && prevStart < getCurrentPhaseDef().myLastEnd) {
     226              :             // phase was started and ended once already in the current cycle
     227              :             // it should not end a second time in the same cycle
     228          334 :             earliest += myDefaultCycleTime;
     229              : #ifdef DEBUG_COORDINATION
     230              :             if (DEBUG_COND) {
     231              :                 std::cout << SIMTIME << " tl=" << getID() << " getEarliest phase=" << myStep
     232              :                           << " prevStart= " << STEPS2TIME(prevStart)
     233              :                           << " prevEnd= " << STEPS2TIME(getCurrentPhaseDef().myLastEnd)
     234              :                           << " cycleStart=" << STEPS2TIME(SIMSTEP - getTimeInCycle()) << " started Twice - move into next cycle\n";
     235              :             }
     236              : #endif
     237              :         } else {
     238         6574 :             SUMOTime latest = getLatestEnd();
     239         6574 :             if (latest != MSPhaseDefinition::UNSPECIFIED_DURATION) {
     240         4492 :                 const SUMOTime minRemaining = getMinDur() - (SIMSTEP - getCurrentPhaseDef().myLastSwitch);
     241         4492 :                 const SUMOTime minEnd = getTimeInCycle() + minRemaining;
     242         4492 :                 if (latest > earliest && latest < minEnd) {
     243              :                     // cannot terminate phase between earliest and latest -> move end into next cycle
     244          164 :                     earliest += myDefaultCycleTime;
     245         4328 :                 } else if (latest < earliest && latest >= minEnd) {
     246              :                     // can ignore earliest since it counts from the previous cycle
     247          288 :                     earliest -= myDefaultCycleTime;
     248              :                 }
     249              : #ifdef DEBUG_COORDINATION
     250              :                 if (DEBUG_COND) {
     251              :                     std::cout << SIMTIME << " tl=" << getID() << " getEarliest phase=" << myStep << " latest=" << STEPS2TIME(latest) << " minEnd="
     252              :                               << STEPS2TIME(minEnd) << " earliest=" << STEPS2TIME(earliest) << "\n";
     253              :                 }
     254              : #endif
     255              :             }
     256              :         }
     257         6908 :         const SUMOTime maxRemaining = getMaxDur() - (SIMSTEP - getCurrentPhaseDef().myLastSwitch);
     258         6908 :         return MIN2(earliest - getTimeInCycle(), maxRemaining);
     259              :     }
     260              : }
     261              : 
     262              : 
     263              : SUMOTime
     264      1307397 : MSSimpleTrafficLightLogic::getLatest() const {
     265      1307397 :     const SUMOTime latest = getLatestEnd();
     266      1307397 :     if (latest == MSPhaseDefinition::UNSPECIFIED_DURATION) {
     267              :         return SUMOTime_MAX; // no restriction
     268              :     } else {
     269       250428 :         if (latest < getEarliestEnd()) {
     270        21656 :             const SUMOTime running = SIMSTEP - getCurrentPhaseDef().myLastSwitch;
     271        21656 :             if (running < getTimeInCycle()) {
     272              :                 // phase was started in the current cycle so the restriction does not apply yet
     273              :                 return SUMOTime_MAX;
     274              :             }
     275              :         }
     276              : #ifdef DEBUG_COORDINATION
     277              :         if (DEBUG_COND) {
     278              :             std::cout << SIMTIME << " tl=" << getID() << " getLatest phase=" << myStep << " latest=" << STEPS2TIME(latest)
     279              :                       << " cycTime=" << STEPS2TIME(getTimeInCycle()) << " res=" << STEPS2TIME(latest - getTimeInCycle()) << "\n";
     280              :         }
     281              : #endif
     282       234550 :         if (latest == myDefaultCycleTime && getTimeInCycle() == 0) {
     283              :             // special case: end on cylce time wrap-around
     284              :             return 0;
     285              :         }
     286       234526 :         return MAX2(SUMOTime(0), latest - getTimeInCycle());
     287              :     }
     288              : }
     289              : 
     290              : 
     291              : 
     292              : // ------------ Changing phases and phase durations
     293              : void
     294         3481 : MSSimpleTrafficLightLogic::changeStepAndDuration(MSTLLogicControl& tlcontrol,
     295              :         SUMOTime simStep, int step, SUMOTime stepDuration) {
     296         3481 :     mySwitchCommand->deschedule(this);
     297         3481 :     mySwitchCommand = new SwitchCommand(tlcontrol, this, stepDuration + simStep);
     298         3481 :     if (step >= 0 && step != myStep) {
     299         1234 :         myStep = step;
     300         1234 :         myPhases[myStep]->myLastSwitch = MSNet::getInstance()->getCurrentTimeStep();
     301         1234 :         if (myAmActive) {
     302              :             // when loading from state, the last loaded program isn't always the active one
     303         1222 :             setTrafficLightSignals(simStep);
     304              :         }
     305         1234 :         tlcontrol.get(getID()).executeOnSwitchActions();
     306              :     }
     307         3481 :     MSNet::getInstance()->getBeginOfTimestepEvents()->addEvent(
     308         3481 :         mySwitchCommand, stepDuration + simStep);
     309         3481 : }
     310              : 
     311              : 
     312              : void
     313           23 : MSSimpleTrafficLightLogic::setPhases(const Phases& phases, int step) {
     314              :     assert(step < (int)phases.size());
     315           23 :     SUMOTime lastSwitch = myPhases[myStep]->getState() == phases[step]->getState() ? myPhases[myStep]->myLastSwitch : SIMSTEP;
     316           23 :     deletePhases();
     317           23 :     myPhases = phases;
     318           23 :     myStep = step;
     319           23 :     myDefaultCycleTime = computeCycleTime(myPhases);
     320           23 :     myPhases[myStep]->myLastSwitch = lastSwitch;
     321           23 : }
     322              : 
     323              : 
     324              : void
     325       116564 : MSSimpleTrafficLightLogic::deletePhases() {
     326       707474 :     for (int i = 0; i < (int)myPhases.size(); i++) {
     327       590910 :         delete myPhases[i];
     328              :     }
     329       116564 : }
     330              : 
     331              : void
     332         1604 : MSSimpleTrafficLightLogic::saveState(OutputDevice& out) const {
     333         1604 :     out.openTag(SUMO_TAG_TLLOGIC);
     334         1604 :     out.writeAttr(SUMO_ATTR_ID, getID());
     335         1604 :     out.writeAttr(SUMO_ATTR_PROGRAMID, getProgramID());
     336         1604 :     out.writeAttr(SUMO_ATTR_PHASE, getCurrentPhaseIndex());
     337         1604 :     out.writeAttr(SUMO_ATTR_DURATION, getSpentDuration());
     338         1604 :     out.writeAttr(SUMO_ATTR_ACTIVE, myAmActive);
     339         1604 :     out.closeTag();
     340         1604 : }
     341              : 
     342              : const std::string
     343      1146518 : MSSimpleTrafficLightLogic::getParameter(const std::string& key, const std::string defaultValue) const {
     344      1146518 :     if (key == "cycleTime") {
     345           10 :         return toString(STEPS2TIME(myDefaultCycleTime));
     346      1146508 :     } else if (key == "offset") {
     347           10 :         return toString(STEPS2TIME(myOffset));
     348      1146498 :     } else if (key == "coordinated") {
     349           10 :         return toString(myCoordinated);
     350      1146488 :     } else if (key == "cycleSecond") {
     351           10 :         return toString(STEPS2TIME(getTimeInCycle()));
     352      1146478 :     } else if (key == "typeName") {
     353           12 :         return toString(this->getLogicType());
     354              :     }
     355      2292932 :     return Parameterised::getParameter(key, defaultValue);
     356              : }
     357              : 
     358              : void
     359          127 : MSSimpleTrafficLightLogic::setParameter(const std::string& key, const std::string& value) {
     360          127 :     if (key == "cycleTime") {
     361            5 :         myDefaultCycleTime = string2time(value);
     362            5 :         Parameterised::setParameter(key, value);
     363          122 :     } else if (key == "cycleSecond" || key == "typeName") {
     364            0 :         throw InvalidArgument(key + " cannot be changed dynamically for traffic light '" + getID() + "'");
     365          122 :     } else if (key == "offset") {
     366            5 :         myOffset = string2time(value);
     367          117 :     } else if (key == "coordinated") {
     368            5 :         myCoordinated = StringUtils::toBool(value);
     369            5 :         Parameterised::setParameter(key, value);
     370              :     } else {
     371          112 :         Parameterised::setParameter(key, value);
     372              :     }
     373          127 : }
     374              : 
     375              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1