LCOV - code coverage report
Current view: top level - src/microsim/traffic_lights - NEMAController.h (source / functions) Coverage Total Hit
Test: lcov.info Lines: 91.4 % 58 53
Test Date: 2026-03-02 16:00:03 Functions: 100.0 % 2 2

            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    NEMAController.h
      15              : /// @author  Tianxin Li
      16              : /// @author  Qichao Wang
      17              : /// @date    August 2020
      18              : ///
      19              : // An actuated NEMA-phase-compliant traffic light logic
      20              : /****************************************************************************/
      21              : #pragma once
      22              : #include <config.h>
      23              : 
      24              : #include <utility>
      25              : #include <vector>
      26              : #include <bitset>
      27              : #include <map>
      28              : #include <set>
      29              : #include <microsim/MSEventControl.h>
      30              : #include <microsim/traffic_lights/MSTrafficLightLogic.h>
      31              : #include "MSSimpleTrafficLightLogic.h"
      32              : #include "microsim/output/MSE2Collector.h"
      33              : #include "MSPhaseDefinition.h"
      34              : 
      35              : 
      36              : // ===========================================================================
      37              : // class declarations
      38              : // ===========================================================================
      39              : class NLDetectorBuilder;
      40              : class MSE2Collector;
      41              : class NEMAPhase;
      42              : class PhaseTransitionLogic;
      43              : 
      44              : // ===========================================================================
      45              : // Enumeration
      46              : // ===========================================================================
      47              : enum class LightState {
      48              :     RedXfer,
      49              :     Red,
      50              :     Yellow,
      51              :     Green,
      52              :     GreenXfer,
      53              :     GreenRest,
      54              : };
      55              : 
      56              : 
      57              : // ===========================================================================
      58              : // class definitions
      59              : // ===========================================================================
      60              : /**
      61              :  * @class NEMALogic
      62              :  * @brief A NEMA (adaptive) traffic light logic based on E2Detector
      63              :  */
      64              : class NEMALogic : public MSSimpleTrafficLightLogic {
      65              : public:
      66              : 
      67              :     typedef NEMAPhase* PhasePtr;
      68              : 
      69              :     typedef std::map<MSLane*, MSE2Collector*> LaneDetectorMap;
      70              : 
      71              :     typedef std::map<MSE2Collector*, MSLane*, ComparatorIdLess> DetectorLaneMap;
      72              : 
      73              :     // Small structure for storing two ring transitions and the average distance
      74              :     struct transitionInfo {
      75              :         PhaseTransitionLogic* p1;
      76              :         PhaseTransitionLogic* p2;
      77              :         float distance;
      78              :     };
      79              : 
      80              :     enum controllerType {
      81              :         Type170,
      82              :         TS2
      83              :     };
      84              : 
      85              :     /// @brief constant for storing the priority order for light heads. Iterates left to right and stops when finds a match.
      86              :     const std::string lightHeadPriority = "GgyuOs";
      87              : 
      88              :     typedef std::vector<transitionInfo> TransitionPairs;
      89              : 
      90              :     /** @brief Constructor
      91              :      * @param[in] tlcontrol The tls control responsible for this tls
      92              :      * @param[in] id This tls' id
      93              :      * @param[in] programID This tls' sub-id (program id)
      94              :      * @param[in] phases Definitions of the phases
      95              :      * @param[in] step The initial phase index
      96              :      * @param[in] delay The time to wait before the first switch
      97              :      * @param[in] parameter The parameter to use for tls set-up
      98              :      */
      99              :     NEMALogic(MSTLLogicControl& tlcontrol,
     100              :               const std::string& id, const std::string& programID,
     101              :               const SUMOTime offset,
     102              :               const MSSimpleTrafficLightLogic::Phases& phases,
     103              :               int step, SUMOTime delay,
     104              :               const std::map<std::string, std::string>& parameter,
     105              :               const std::string& basePath);
     106              : 
     107              : 
     108              :     /** @brief Initialises the tls with information about incoming lanes
     109              :      * @param[in] nb The detector builder
     110              :      * @exception ProcessError If something fails on initialisation
     111              :      */
     112              :     void init(NLDetectorBuilder& nb) override;
     113              : 
     114              :     /// @brief Destructor
     115              :     ~NEMALogic();
     116              : 
     117              :     /// @brief overrides the MSSimpleTrafficLightLogic trySwitch method
     118              :     SUMOTime trySwitch() override;
     119              : 
     120              :     /// @name Dynamic Information Retrieval
     121              :     /// @{
     122              : 
     123              :     /** @brief Returns myPhase, which doesn't correspond to a NEMA phase, but rather the composite light string
     124              :      * @return The current phase (NEMA controller really uses )
     125              :      */
     126              :     const MSPhaseDefinition& getCurrentPhaseDef() const override;
     127              :     /// @}
     128              : 
     129              :     void resetLastSwitch(SUMOTime t); 
     130              : 
     131              :     void activateProgram() override;
     132              :     void deactivateProgram() override;
     133              : 
     134              :     bool showDetectors() const {
     135            0 :         return myShowDetectors;
     136              :     }
     137              : 
     138              :     void setShowDetectors(bool show);
     139              : 
     140              :     /// @brief retrieve all detectors used by this program
     141              :     std::map<std::string, double> getDetectorStates() const override;
     142              : 
     143              :     /**
     144              :      * @brief extends the transitions vector with valid Transitions given the current traffic light state
     145              :      *
     146              :      * @param[out] transitions a reference to the TransitionPairs vector
     147              :      */
     148              :     void getNextPhases(TransitionPairs& transitions);
     149              : 
     150              :     /**
     151              :      * @brief Calculates the modulus a / b, normally used to calculate the cycle time between
     152              :      * two times. Usage example:  ModeCycle(t1 - t2, cycleLength)
     153              :      *
     154              :      * @param a time 1
     155              :      * @param b time 2
     156              :      * @return SUMOTime
     157              :      */
     158              :     SUMOTime ModeCycle(SUMOTime a, SUMOTime b);
     159              : 
     160              : 
     161              :     /**
     162              :      * @brief returns the IDs of the phase's controlled lanes.
     163              :      * Found by looking for the "G" in the light state string
     164              :      *
     165              :      * @param state the light state string
     166              :      * @return std::set<std::string>
     167              :      */
     168              :     void getLaneInfoFromNEMAState(std::string state, StringVector& laneIDs, IntVector& stateIndex);
     169              : 
     170              :     /**
     171              :      * @brief Set the max green of all phases.
     172              :      *
     173              :      * @param newMaxGreens a vector of new max green times. Must be length 8
     174              :      */
     175              :     void setNewMaxGreens(std::vector<double> newMaxGreens);
     176              : 
     177              :     /**
     178              :      * @brief Set the new splits of all phases
     179              :      *
     180              :      * @param newSplits a vector of new splits. Must be length 8
     181              :      */
     182              :     void setNewSplits(std::vector<double> newSplits);
     183              : 
     184              :     /**
     185              :      * @brief set the new cycle length for the controller
     186              :      *
     187              :      * @param newCycleLength
     188              :      */
     189              :     void setNewCycleLength(double newCycleLength);
     190              : 
     191              :     /**
     192              :      * @brief Set the new offset for the controller
     193              :      *
     194              :      * @param newOffset
     195              :      */
     196              :     void setNewOffset(double newOffset);
     197              : 
     198              :     /**
     199              :      * @brief Get the current cycle length
     200              :      *
     201              :      * @return SUMOTime
     202              :      */
     203              :     SUMOTime getCurrentCycleLength() {
     204        24892 :         return myCycleLength;
     205              :     }
     206              : 
     207              :     /// @brief try to set the given parameter. Parameters prefixed with 'NEMA.' control functionality
     208              :     void setParameter(const std::string& key, const std::string& value) override;
     209              : 
     210              :     /// @brief try to get the value of the given parameter. Parameters prefixed with 'NEMA.' control functionality
     211              :     const std::string getParameter(const std::string& key, const std::string defaultValue = "") const override;
     212              : 
     213              :     /// @brief Wrapper Function to Simplify Accessing Time
     214              :     inline SUMOTime getCurrentTime(void) const {
     215       904592 :         return simTime;
     216              :     }
     217              : 
     218              :     // /// @brief Wrapper Function to Simplify Accessing Offset Cycle Time
     219              :     // inline SUMOTime getCurrentOffsetTime(void) const {return simTime - cycleRefPoint - offset; };
     220              : 
     221              :     /// @brief override Function to Simplify Accessing Offset Cycle Time
     222              :     inline SUMOTime getTimeInCycle() const {
     223        77486 :         return (simTime - cycleRefPoint - offset) % myCycleLength;
     224              :     }
     225              : 
     226              : 
     227              :     /// @brief set the active phase
     228              :     void setActivePhase(PhasePtr phase);
     229              : 
     230              :     /**
     231              :      * @brief Get the Active Phase object for a specified ring
     232              :      *
     233              :      * @param ringNum
     234              :      * @return PhasePtr
     235              :      */
     236              :     inline PhasePtr getActivePhase(int ringNum) {
     237              :         return myActivePhaseObjs[ringNum];
     238              :     }
     239              : 
     240              :     /**
     241              :      * @brief get all phases for a given ring
     242              :      *
     243              :      * @param ringNum
     244              :      * @return std::vector<PhasePtr>
     245              :      */
     246              :     std::vector<PhasePtr> getPhasesByRing(int ringNum);
     247              : 
     248              :     /**
     249              :      * @brief get the phase object matching the phaseNum
     250              :      * If ringNum is passed, it will only search for the phase in the given ring
     251              :      *
     252              :      * @param phaseNum an integer corresponding to the phase
     253              :      * @param ringNum the ring to search for the phase in. Defaults to -1, meaning both rings will be searched
     254              :      * @return PhasePtr (NEMAPhase*)
     255              :      */
     256              :     PhasePtr getPhaseObj(int phaseNum, int ringNum = -1);
     257              : 
     258              :     /**
     259              :      * @brief get a vector of all phase objects
     260              :      *
     261              :      * @return std::vector<PhasePtr>
     262              :      */
     263              :     inline std::vector<PhasePtr> getPhaseObjs(void) {
     264        58228 :         return myPhaseObjs;
     265              :     }
     266              : 
     267              :     /**
     268              :      * @brief return the ring distance between two phases
     269              :      *
     270              :      * @param p1 phase 1
     271              :      * @param p2 phase 2
     272              :      * @param ringNum the ring on which to measure the phase distance
     273              :      * @return int
     274              :      */
     275              :     int measureRingDistance(int p1, int p2, int ringNum);
     276              : 
     277              :     /**
     278              :      * @brief checks if the controller is of type170
     279              :      *
     280              :      * @return true if myControllerType == Type170
     281              :      * @return false
     282              :      */
     283              :     inline bool isType170(void) const {
     284        14330 :         return myControllerType == Type170;
     285              :     }
     286              : 
     287              :     /**
     288              :      * @brief Get the opposite active phase
     289              :      *
     290              :      * @param p a pointer to the known phase
     291              :      * @return PhasePtr
     292              :      */
     293              :     PhasePtr getOtherPhase(PhasePtr p);
     294              : 
     295              :     /// @brief whether the controller is in coordinated mode or not
     296              :     bool coordinateMode;
     297              : 
     298              :     /**
     299              :      * @brief implement any pending traci changes
     300              :      * This function is called once per cycle
     301              :      */
     302              :     void implementTraciChanges(void);
     303              : 
     304              :     /// @brief a store of the coordinated phase objects. Only used meaningfully when the controller is
     305              :     /// in coordinated mode
     306              :     PhasePtr coordinatePhaseObjs[2];
     307              : 
     308              : protected:
     309              : 
     310              :     /// @brief flag to keep track of whether a timing change has been requested via traci
     311              :     bool queuedTraciChanges;
     312              : 
     313              :     /// @brief the controller's offset
     314              :     SUMOTime offset;
     315              :     /// @brief the next offset to implement
     316              :     SUMOTime myNextOffset;
     317              : 
     318              :     /// @brief the coordinated cycle length
     319              :     SUMOTime myCycleLength;
     320              :     /// @brief the next cycle length (set by traci)
     321              :     SUMOTime myNextCycleLength;
     322              : 
     323              :     /// @brief stores the simulation time to make it easily accessible
     324              :     SUMOTime simTime = 0;
     325              : 
     326              :     /// @brief stores controllers # of rings
     327              :     int myNumberRings;
     328              : 
     329              :     /// @brief stores the length of phase string for the controller "GGrrrrs" = 6. Must be the same length for all phases
     330              :     int myPhaseStrLen = -1;
     331              : 
     332              :     /// @brief Set the simTime
     333              :     inline void setCurrentTime(void) {
     334       396940 :         simTime = MSNet::getInstance()->getCurrentTimeStep();
     335              :     }
     336              : 
     337              :     /// @brief variable to store the active phases
     338              :     PhasePtr myActivePhaseObjs[2] = { nullptr, nullptr };
     339              : 
     340              :     /// @brief a vector that stores a pointer to the instantiated NEMAPhase objects
     341              :     std::vector<PhasePtr > myPhaseObjs;
     342              : 
     343              :     /// @brief an array to store the phases located at a barrier for each ring
     344              :     PhasePtr defaultBarrierPhases[2][2];
     345              : 
     346              :     /**
     347              :      * Construct Timing and Phase Defs
     348              :      * @brief constructs phase using the configuration file
     349              :      * @param barriers a string of barrier phases ("4,8")
     350              :      * @param coordinates a string of coordinated phases ("2,6")
     351              :      * @param ring1 a string of phases in ring 1 ("1,2,3,4")
     352              :      * @param ring2 a string of phases in ring 2 ("5,6,7,8")
     353              :      */
     354              :     void constructTimingAndPhaseDefs(std::string& barriers, std::string& coordinates,
     355              :                                      std::string& ring1, std::string& ring2);
     356              : 
     357              :     /** @brief iterates over the two active phases (myActivePhaseObjs) and merges the two active phases
     358              :      * @return std::string the light string to implement (GGGrrrGGGrrr)
     359              :      */
     360              :     std::string composeLightString();
     361              : 
     362              :     /** @brief check if a vector contains an element
     363              :      * @param v the vector of phase numbers
     364              :      * @param phaseNum the phase number
     365              :      * @return bool
     366              :      */
     367              :     bool vectorContainsPhase(std::vector<int> v, int phaseNum);
     368              : 
     369              :     // create a small datatype for mapping detector to phase index
     370              :     // This is the one copied from MSActuatedTrafficLightLogic
     371              :     // not used in our controller, but it is here for meeting the SUMO default traffic logic light check
     372              :     // this one and related could be removed with extra efforts
     373         4918 :     struct DetectorInfo {
     374         1126 :         DetectorInfo(MSE2Collector* _det, int numPhases) :
     375         1126 :             det(_det),
     376         1126 :             servedPhase(numPhases, false)
     377              :         {}
     378              :         MSE2Collector* det;
     379              :         SUMOTime lastGreenTime = 0;
     380              :         std::vector<bool> servedPhase;
     381              :     };
     382              :     typedef std::vector<std::vector<DetectorInfo*>> detectorMap;
     383              :     detectorMap myDetectorForPhase;
     384              :     /// @brief storing the detector info in a vector
     385              :     std::vector<DetectorInfo> myDetectorInfoVector;
     386              : 
     387              : 
     388              :     /// @brief return whether there is a major link from the given lane in the given phase
     389              :     bool hasMajor(const std::string& state, const LaneVector& lanes) const;
     390              : 
     391              :     /**
     392              :      * @brief converts a comma separated string into a integer vector
     393              :      * "1,2,3,4" -> {1,2,3,4}
     394              :      *
     395              :      * @param s the string of comma separated integers
     396              :      * @return std::vector<int>
     397              :      */
     398              :     std::vector<int> readParaFromString(std::string s);
     399              : 
     400              :     /**
     401              :      * @brief decide whether the detector is for left turn lane
     402              :      * if it is, use the detector length for left turn lane
     403              :      *
     404              :      * @param lane a pointer to the lane
     405              :      * @return whether a lane is a left turn or not
     406              :      */
     407              :     bool isLeftTurnLane(const MSLane* const lane) const;
     408              : 
     409              :     /// @brief convert a string to an integer
     410              :     int string2int(std::string s);
     411              : 
     412              :     /// @brief A map from lanes to detectors
     413              :     LaneDetectorMap myLaneDetectorMap;
     414              : 
     415              :     /// @brief A map from lanes names to phases
     416              :     std::map<std::string, int> myLanePhaseMap;
     417              : 
     418              :     /// @brief A map from detectors to lanes
     419              :     DetectorLaneMap myDetectorLaneMap;
     420              : 
     421              :     /// @brief store the generated detector length
     422              :     double myDetectorLength;
     423              : 
     424              :     /// @brief store the left turn lane detestor length
     425              :     double myDetectorLengthLeftTurnLane;
     426              : 
     427              :     /// Whether the detectors shall be shown in the GUI
     428              :     bool myShowDetectors;
     429              : 
     430              :     /// The output file for generated detectors
     431              :     std::string myFile;
     432              : 
     433              :     /// The frequency for aggregating detector output
     434              :     SUMOTime myFreq;
     435              : 
     436              :     /// Whether detector output separates by vType
     437              :     std::string myVehicleTypes;
     438              : 
     439              :     /*
     440              :     {
     441              :         {3,4,1,2},
     442              :         {7,8,5,6}
     443              :     }
     444              :     */
     445              :     std::vector<std::vector<int>> rings;
     446              : 
     447              :     /*
     448              :     {
     449              :         {1 : PhaseDetectorInfo{
     450              :                 detectors: {det1, det2, ...},
     451              :                 crossPhaseDetector: 6
     452              :             },
     453              :         },
     454              :         {2 : ...
     455              :     }
     456              :     */
     457              :     // std::map<int, PhaseDetectorInfo> phase2DetectorMap;
     458              :     std::map<int, std::vector<std::string>> phase2ControllerLanesMap;
     459              : 
     460              :     bool fixForceOff;
     461              :     SUMOTime cycleRefPoint;// missing update
     462              :     bool whetherOutputState;
     463              :     bool ignoreErrors;
     464              : 
     465              :     /**
     466              :      * @brief return the default transition for t give its and the ot's state
     467              :      *
     468              :      * @param t the target phase
     469              :      * @param ot the other active phase
     470              :      * @return PhaseTransitionLogic* the transition logic describing this transition
     471              :      */
     472              :     PhaseTransitionLogic* getDefaultTransition(PhaseTransitionLogic* t, PhaseTransitionLogic* ot);
     473              : 
     474              :     // Store the cabinet type
     475              :     controllerType myControllerType;
     476              : 
     477              :     /**
     478              :      * @brief parse the controllerType from the tllogic description
     479              :      *
     480              :      * @param inputType
     481              :      * @return controllerType
     482              :      */
     483              :     controllerType parseControllerType(std::string inputType);
     484              : 
     485              :     /// @brief virtual phase that holds the current state
     486              :     MSPhaseDefinition myPhase;
     487              : 
     488              :     /**
     489              :      * @brief throw an InvalidArgument error if the param_name is not set
     490              :      *
     491              :      * @param param_variable the value of param_name
     492              :      * @param param_name  the name of the parameter
     493              :      */
     494              :     void error_handle_not_set(std::string param_variable, std::string param_name);
     495              : 
     496              :     /**
     497              :      * @brief validates the NEMA timing.
     498              :      * Writes warnings if ignoreError set to true else throws ProcessError
     499              :      *
     500              :      */
     501              :     void validate_timing();
     502              : 
     503              :     /**
     504              :      * @brief calculate the forceOffs for a TS2 style offset
     505              :      * From https://ops.fhwa.dot.gov/publications/fhwahop08024/chapter6.htm#6.3
     506              :      *
     507              :      */
     508              :     void calculateForceOffsTS2();
     509              :     /**
     510              :      * @brief calculate the forceOffs for a Type 170 style offset
     511              :      * From https://ops.fhwa.dot.gov/publications/fhwahop08024/chapter6.htm#6.3
     512              :      */
     513              :     void calculateForceOffs170();
     514              : 
     515              :     /// @brief directs the code to the correct force off function accorifing to its cabinet type
     516          136 :     void calculateForceOffs() {
     517          136 :         switch (myControllerType) {
     518           38 :             case Type170:
     519           38 :                 return calculateForceOffs170();
     520           98 :             case TS2:
     521           98 :                 return calculateForceOffsTS2();
     522            0 :             default:
     523            0 :                 return calculateForceOffs170();
     524              :         }
     525              :     }
     526              : 
     527              : 
     528              :     /// @brief calculate the initial phases for the TS2 style controller to start in
     529              :     void calculateInitialPhasesTS2();
     530              :     /// @brief calculate the initial phases for Type 170
     531              :     void calculateInitialPhases170();
     532              :     /// @brief directs the controller to the correct calculate phases function
     533           46 :     void calculateInitialPhases() {
     534           46 :         switch (myControllerType) {
     535           22 :             case Type170:
     536           22 :                 return calculateInitialPhases170();
     537           24 :             case TS2:
     538           24 :                 return calculateInitialPhasesTS2();
     539            0 :             default:
     540              :                 // Default to Type170
     541            0 :                 return calculateInitialPhases170();
     542              :         }
     543              :     }
     544              : };
     545              : 
     546              : 
     547              : /**
     548              :  * @class NEMAPhase
     549              :  * @brief One phase in the NEMAController
     550              :  *
     551              :  * This represents one phase and all its parameters in a NEMA traffic light
     552              :  * The phase ultimately controls its transition to the next phase,
     553              :  * and is resbonisble for determining the valid transitions given its current state
     554              :  */
     555              : class NEMAPhase {
     556              : public:
     557              :     /// @brief Typedef for commonly used phase pointer
     558              :     typedef NEMAPhase* PhasePtr;
     559              : 
     560              :     /// @struct PhaseDetectorInfo
     561              :     /// @brief stores information about the phase's detector(s)
     562         1196 :     struct PhaseDetectorInfo {
     563          618 :         PhaseDetectorInfo() :
     564              :             detectors(),
     565          618 :             cpdTarget(),
     566          618 :             cpdSource(),
     567          618 :             detectActive(),
     568          618 :             latching()
     569              :         {}
     570          600 :         PhaseDetectorInfo(bool latching, PhasePtr cpdSource, PhasePtr cpdTarget) :
     571          600 :             cpdTarget(cpdTarget),
     572          600 :             cpdSource(cpdSource),
     573          600 :             detectActive(false),
     574          600 :             latching(latching)
     575              :         {}
     576              :         ///@brief a vector of pointers to the phase's detectors
     577              :         std::vector<MSE2Collector*> detectors;
     578              :         /// @brief the cross-phase switching target for myself (6 if 6 should check 1 if 6 is green and I am phase 1)
     579              :         PhasePtr cpdTarget;
     580              :         /// @brief the cross-phase switching source for myself  (1 if 6 should check 1 if 6 is green and I am phase 6)
     581              :         PhasePtr cpdSource;
     582              :         /// @brief where any of my detectors are active or not
     583              :         bool detectActive;
     584              :         /// @brief whether the detectors are latching or not
     585              :         bool latching;
     586              :     };
     587              : 
     588              :     // create a PhaseDetectorInfo type
     589              :     typedef PhaseDetectorInfo PhaseDetectorInfo;
     590              : 
     591              :     /**
     592              :      * @brief Construct a new NEMAPhase object
     593              :      *
     594              :      * @param phaseName the "name" of the phase as an integer
     595              :      * @param isBarrier if the phase is located at a barrier or not
     596              :      * @param isGreenRest if it is a phase in which the traffic signal can green rest
     597              :      * @param isCoordinated if it is a coordinated phase
     598              :      * @param minRecall whether or not the phase has minimum recall or not
     599              :      * @param maxRecall whether or not the phase has maximum recall or not
     600              :      * @param fixForceOff if the phase has a force off or not
     601              :      * @param barrierNum the barrier to which the phase belongs (0 or 1)
     602              :      * @param ringNum the ring to which the phase belongs (0 or 1)
     603              :      * @param phaseStringInds the indexes of lanes that I control, ie. "srrrrGG" is {5, 6}
     604              :      * @param phase the MSPhaseDefinition base class
     605              :      */
     606              :     NEMAPhase(int phaseName,
     607              :               bool isBarrier,
     608              :               bool isGreenRest,
     609              :               bool isCoordinated,
     610              :               bool minRecall,
     611              :               bool maxRecall,
     612              :               bool fixForceOff,
     613              :               int barrierNum,
     614              :               int ringNum,
     615              :               IntVector phaseStringInds,
     616              :               MSPhaseDefinition* phase);
     617              : 
     618              :     /// @brief Destructor
     619              :     ~NEMAPhase();
     620              : 
     621              :     /// @brief gets the current light state
     622              :     inline LightState getCurrentState() const {
     623       177103 :         return myLightState;
     624              :     }
     625              :     /// @brief returns a vector of the phases detectors
     626              :     inline std::vector<MSE2Collector*> getDetectors() const {
     627          964 :         return myDetectorInfo.detectors;
     628              :     }
     629              : 
     630              : 
     631              :     /// @brief sets the detectors for the phase
     632              :     inline void setDetectors(std::vector<MSE2Collector*> detectors) {
     633          574 :         myDetectorInfo.detectors = detectors;
     634          574 :     }
     635              : 
     636              :     /// @brief check if a transition is active
     637              :     inline bool isTransitionActive() const {
     638         8030 :         return myLightState < LightState::Green;
     639              :     }
     640              : 
     641              :     // Build a Map of Valid Transitions and store the detector-based information
     642              :     /**
     643              :      * @brief initializes the object
     644              :      *
     645              :      * @param controller a pointer to the controller object
     646              :      * @param crossPhaseTarget the cross phase switching target
     647              :      * @param crossPhaseSource the cross phase switching source
     648              :      * @param latching whether the phase has latching detectors or not
     649              :      */
     650              :     void init(NEMALogic* controller, int crossPhaseTarget, int crossPhaseSource, bool latching);
     651              : 
     652              :     /**
     653              :      * @brief update is called on the active phases by the NEMAController at every time step
     654              :      *
     655              :      * @param controller a reference to the controller
     656              :      */
     657              :     void update(NEMALogic* controller);
     658              : 
     659              :     /**
     660              :      * @brief handles the transition out of a phase into the next (puts the phase through (G -> Y -> R) transition
     661              :      *
     662              :      * @param controller a reference to the NEMAController
     663              :      * @param nextPhases the next phases that the controller wants to transition to
     664              :      */
     665              :     void exit(NEMALogic* controller, PhaseTransitionLogic* nextPhases[2]);
     666              : 
     667              :     /**
     668              :      * @brief handles the transition into a green rest state
     669              :      *
     670              :      * @param controller a reference to the NEMAController
     671              :      * @param nextPhases the next phases that the controller wants to transition to
     672              :      */
     673              :     void handleGreenRestOrTransfer(NEMALogic* controller, PhaseTransitionLogic* nextPhases[2]);
     674              : 
     675              :     /**
     676              :      * @brief handles the transition into yellow
     677              :      *
     678              :      * @param controller a reference to the NEMAController
     679              :      */
     680              :     void enterYellow(NEMALogic* controller);
     681              : 
     682              :     /**
     683              :      * @brief handles the transition into a red xfer state, which is roughly the same as green rest
     684              :      *
     685              :      * @param controller a reference to the NEMAController
     686              :      */
     687              :     void handleRedXferOrNextPhase(NEMALogic* controller, PhaseTransitionLogic* nextPhases[2]);
     688              : 
     689              :     /// @brief simple method to check if there is a recall on the phase.
     690              :     inline bool hasRecall(void) {
     691              :         return minRecall || maxRecall;
     692              :     }
     693              : 
     694              :     /// @brief simple method to check if there is either a recall or an active detector
     695              :     inline bool callActive(void) {
     696       833179 :         return minRecall || maxRecall || myDetectorInfo.detectActive;
     697              :     }
     698              : 
     699              :     /// @brief simple method to check if a detector is active
     700              :     inline bool detectActive(void) {
     701              :         return myDetectorInfo.detectActive;
     702              :     }
     703              : 
     704              :     /// @brief Check Detectors. Called on all phases at every step
     705              :     void checkMyDetectors(void);
     706              : 
     707              :     /// @brief Clear My Detectors. Called on all phases at every step
     708              :     void clearMyDetectors(void);
     709              : 
     710              :     // Need-to-know Phase Settings
     711              :     int phaseName;
     712              :     bool isAtBarrier;
     713              :     bool isGreenRest;
     714              :     int barrierNum;
     715              :     bool coordinatePhase;
     716              :     bool minRecall;
     717              :     bool maxRecall;
     718              :     bool fixForceOff;
     719              :     int ringNum;
     720              : 
     721              :     /// @brief store the last detect check for traci purposes
     722              :     bool lastDetectActive;
     723              : 
     724              :     /// @brief a count down timer to track green rest transition time
     725              :     SUMOTime greenRestTimer;
     726              :     SUMOTime greatestStartTime;
     727              :     /// @brief stores the force off time in coordinated mode
     728              :     SUMOTime forceOffTime;
     729              : 
     730              :     /// @brief flag to for the supervisory controller to denote whether phase is ready to switch or not.
     731              :     bool readyToSwitch;
     732              : 
     733              :     /**
     734              :      * @brief Get the Transition Time
     735              :      *
     736              :      * @param controller
     737              :      * @return SUMOTime
     738              :      */
     739              :     SUMOTime getTransitionTime(NEMALogic* controller);
     740              : 
     741              :     /**
     742              :      * @brief Get the Transition time given
     743              :      *
     744              :      * @param controller
     745              :      * @return SUMOTime
     746              :      */
     747              :     inline SUMOTime getTransitionTimeStateless(void) {
     748        14112 :         return yellow + red;
     749              :     }
     750              : 
     751              :     /// @brief get the prior phase
     752              :     inline PhasePtr getSequentialPriorPhase(void) {
     753         6192 :         return sequentialPriorPhase;
     754              :     }
     755              : 
     756              :     /// @brief set the prior phase
     757              :     inline void setSequentialPriorPhase(PhasePtr priorPhase) {
     758          230 :         sequentialPriorPhase = priorPhase;
     759          388 :     }
     760              : 
     761              :     /**
     762              :      * @brief calculate a vector of potention next phases
     763              :      *
     764              :      * @param controller
     765              :      * @return std::vector<PhaseTransitionLogic*>
     766              :      */
     767              :     std::vector<PhaseTransitionLogic*> trySwitch(NEMALogic* controller);
     768              : 
     769              :     /**
     770              :      * @brief return the PhaseTransitionLogic matching the toPhase
     771              :      *
     772              :      * @param toPhase a integer representing the target phase
     773              :      * @return PhaseTransitionLogic*
     774              :      */
     775              :     PhaseTransitionLogic* getTransition(int toPhase);
     776              : 
     777              :     /// @brief Return the ryg light string for the phase
     778              :     char getNEMAChar(int i);
     779              : 
     780              :     /// @brief accessory function to recalculate timing
     781              :     void recalculateTiming(void);
     782              : 
     783              :     /// @brief Force Enter. This Should only be called at initialization time
     784              :     inline void forceEnter(NEMALogic* controller) {
     785          178 :         enter(controller, sequentialPriorPhase);
     786          132 :     }
     787              : 
     788              :     /// @brief Return whether or not the phase index is controlled by me
     789              :     inline bool controlledIndex(int i) {
     790              :         return std::count(myPhaseStringInds.begin(), myPhaseStringInds.end(), i) > 0;
     791              :     }
     792              : 
     793              :     ///  @name Basic Phase Timing Parameters
     794              :     /// @{
     795              :     SUMOTime yellow;
     796              :     SUMOTime red;
     797              :     SUMOTime minDuration;
     798              :     SUMOTime maxDuration;
     799              :     SUMOTime nextMaxDuration;
     800              :     SUMOTime vehExt;
     801              :     /// @}
     802              : 
     803              :     /// @brief public method to set whether phase is active or not
     804              :     inline void cleanupExit(void) {
     805        54808 :         transitionActive = false;
     806        54808 :         readyToSwitch = false;
     807        54808 :         myLightState = LightState::Red;
     808              :     }
     809              : 
     810              :     /// @brief simple internal check to see if done okay to transition
     811              :     inline bool okay2ForceSwitch(NEMALogic* controller) {
     812        62304 :         return readyToSwitch && !transitionActive && (getTransitionTime(controller) <= TIME2STEPS(0));
     813              :     }
     814              : 
     815              : private:
     816              :     /// @brief A reference to the core phase of which NEMAPhase wraps
     817              :     MSPhaseDefinition* myCorePhase = nullptr;
     818              : 
     819              :     /// @name store references to myself, the last phase I was in, and the sequentially next phase
     820              :     /// @{
     821              :     PhasePtr myInstance = nullptr;
     822              :     PhasePtr myLastPhaseInstance = nullptr;
     823              :     PhasePtr sequentialPriorPhase = nullptr;
     824              :     /// @}
     825              : 
     826              :     // Phase Knowledge Space
     827              :     LightState myLightState;
     828              :     PhaseDetectorInfo myDetectorInfo;
     829              : 
     830              :     /// @name Timing Parameters
     831              :     /// @{
     832              :     SUMOTime maxGreenDynamic;
     833              :     SUMOTime myStartTime;
     834              :     SUMOTime myExpectedDuration;
     835              :     SUMOTime myLastEnd;
     836              :     /// @}
     837              : 
     838              :     /// @name Light String Parameters
     839              :     /// @{
     840              :     IntVector myPhaseStringInds;
     841              :     std::string myGreenString;
     842              :     std::string myYellowString;
     843              :     std::string myRedString;
     844              :     /// }
     845              : 
     846              :     /**
     847              :      * @brief Applies the vehicle extension timer if appropriate
     848              :      *
     849              :      * @param duration the current phase duration
     850              :      * @return SUMOTime
     851              :      */
     852              :     SUMOTime calcVehicleExtension(SUMOTime duration);
     853              : 
     854              :     /// @brief stores a sorted list of potential transitions
     855              :     std::vector<PhaseTransitionLogic*> myTransitions;
     856              : 
     857              :     /**
     858              :      * @brief handles entry to the phase during simulation
     859              :      * Sets the color to green and determines maximum duration
     860              :      *
     861              :      * @param controller a reference to the controller
     862              :      * @param lastPhase a reference to the last phase
     863              :      */
     864              :     void enter(NEMALogic* controller, PhasePtr lastPhase);
     865              : 
     866              :     /**
     867              :      * @brief this function replaces getNEMAStates calculation at every call
     868              :      * It sets my myGreenString, myYellowString, and myRedString on class creation
     869              :     */
     870              :     void setMyNEMAStates(void);
     871              : 
     872              :     /// @brief variable to store whether a transition is active or not
     873              :     bool transitionActive;
     874              : 
     875              :     /// @brief pointer to save the last transition
     876              :     PhaseTransitionLogic* lastTransitionDecision;
     877              : 
     878              : };
     879              : 
     880              : 
     881              : /**
     882              :  * @class PhaseTransitionLogic
     883              :  * @brief This class handles the transition logic between two phases
     884              :  *
     885              :  * This is intended to be extensible in the future. Each phase stores some
     886              :  * number of PhaseTransitionLogics, equal to the number of non-zero phases in a ring
     887              :  *
     888              :  */
     889              : class PhaseTransitionLogic {
     890              : public:
     891              :     /// @brief Typedef for commonly used phase pointer
     892              :     typedef NEMAPhase* PhasePtr;
     893              : 
     894              :     /**
     895              :      * @brief Construct a new Phase Transition Logic object
     896              :      *
     897              :      * @param fromPhase the phase who "owns" this transition
     898              :      * @param toPhase the phase to which I represent a transition to
     899              :      */
     900              :     PhaseTransitionLogic(
     901              :         PhasePtr fromPhase,
     902              :         PhasePtr toPhase
     903              :     );
     904              : 
     905              :     /**
     906              :      * @brief This function is the main PhaseTransitionLogic function
     907              :      * It is called by the fromPhase to check if a transition to the toPhase is acceptable
     908              :      *
     909              :      * @param controller a reference to the controller
     910              :      * @return true
     911              :      * @return false
     912              :      */
     913              :     bool okay(NEMALogic* controller);
     914              : 
     915              :     /**
     916              :      * @brief return the ring distance that this transition represents
     917              :      *
     918              :      * @param otherTrans the other PhaseTransitionLogic
     919              :      * @return int
     920              :      */
     921              :     int getDistance(PhaseTransitionLogic* otherTrans);
     922              :     /// @brief set the transition distance
     923              :     inline void setDistance(int d) {
     924         1768 :         distance = d;
     925              :     }
     926              :     int distance;
     927              : 
     928              :     /// @brief deconstructor
     929         1723 :     ~PhaseTransitionLogic() {};
     930              : 
     931              :     /// @brief get the to phase
     932              :     inline PhasePtr getToPhase(void) const {
     933      1049263 :         return toPhase;
     934              :     }
     935              : 
     936              :     /// @brief get the from phase
     937              :     inline PhasePtr getFromPhase(void) const {
     938          624 :         return fromPhase;
     939              :     }
     940              : 
     941              : private:
     942              :     PhasePtr fromPhase;
     943              :     PhasePtr toPhase;
     944              : 
     945              :     /// @brief build the transition logic based on the from and to phase
     946              :     void buildLogic(void);
     947              : 
     948              :     /**
     949              :      * @brief If the fromPhase is at a barrier, then this function
     950              :      * will be called to check whether the transition is valid
     951              :      *
     952              :      * @param controller a reference to the controller
     953              :      * @return true
     954              :      * @return false
     955              :      */
     956              :     bool fromBarrier(NEMALogic* controller);
     957              : 
     958              :     /**
     959              :      * @brief if the fromPhase is a coordinated phase, then
     960              :      * this logic will be checked
     961              :      *
     962              :      * @param controller
     963              :      * @return true
     964              :      * @return false
     965              :      */
     966              :     bool fromCoord(NEMALogic* controller);
     967              : 
     968              :     /**
     969              :      * @brief this represents the bare minimum logic,
     970              :      * that the toPhase has an active detector and that the fromPhase is ready to switch
     971              :      *
     972              :      * @param controller
     973              :      * @return true
     974              :      * @return false
     975              :      */
     976              :     bool freeBase(NEMALogic* controller);
     977              : 
     978              :     /**
     979              :      * @brief represents the bare minimum coordinate mode logic.
     980              :      * Requires that the toPhase can fit its minimum green time before the force off
     981              :      *
     982              :      * @param controller
     983              :      * @return true
     984              :      * @return false
     985              :      */
     986              :     bool coordBase(NEMALogic* controller);
     987              : };
        

Generated by: LCOV version 2.0-1