LCOV - code coverage report
Current view: top level - src/microsim/traffic_lights - NEMAController.h (source / functions) Hit Total Coverage
Test: lcov.info Lines: 53 58 91.4 %
Date: 2024-05-19 15:37:39 Functions: 2 2 100.0 %

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

Generated by: LCOV version 1.14