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: 2024-11-22 15:46:21 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-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        12705 :         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       229161 :         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        38561 :         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        28614 :         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         7385 :         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        87009 :         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         2294 :     struct DetectorInfo {
     373          537 :         DetectorInfo(MSE2Collector* _det, int numPhases) :
     374          537 :             det(_det),
     375          537 :             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           91 :     void calculateForceOffs() {
     516           91 :         switch (myControllerType) {
     517           19 :             case Type170:
     518           19 :                 return calculateForceOffs170();
     519           72 :             case TS2:
     520           72 :                 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           33 :     void calculateInitialPhases() {
     533           33 :         switch (myControllerType) {
     534           11 :             case Type170:
     535           11 :                 return calculateInitialPhases170();
     536           22 :             case TS2:
     537           22 :                 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          695 :     struct PhaseDetectorInfo {
     562          381 :         PhaseDetectorInfo() :
     563              :             detectors(),
     564          381 :             cpdTarget(),
     565          381 :             cpdSource(),
     566          381 :             detectActive(),
     567          381 :             latching()
     568              :         {}
     569          354 :         PhaseDetectorInfo(bool latching, PhasePtr cpdSource, PhasePtr cpdTarget) :
     570          354 :             cpdTarget(cpdTarget),
     571          354 :             cpdSource(cpdSource),
     572          354 :             detectActive(false),
     573          354 :             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        86206 :         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          341 :         myDetectorInfo.detectors = detectors;
     633          341 :     }
     634              : 
     635              :     /// @brief check if a transition is active
     636              :     inline bool isTransitionActive() const {
     637         4247 :         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       276261 :         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         7085 :         return yellow + red;
     748              :     }
     749              : 
     750              :     /// @brief get the prior phase
     751              :     inline PhasePtr getSequentialPriorPhase(void) {
     752         3122 :         return sequentialPriorPhase;
     753              :     }
     754              : 
     755              :     /// @brief set the prior phase
     756              :     inline void setSequentialPriorPhase(PhasePtr priorPhase) {
     757          137 :         sequentialPriorPhase = priorPhase;
     758          224 :     }
     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          101 :         enter(controller, sequentialPriorPhase);
     785           68 :     }
     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         6255 :         transitionActive = false;
     805         6255 :         readyToSwitch = false;
     806         6255 :         myLightState = LightState::Red;
     807              :     }
     808              : 
     809              :     /// @brief simple internal check to see if done okay to transition
     810              :     inline bool okay2ForceSwitch(NEMALogic* controller) {
     811         5888 :         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         1022 :         distance = d;
     924              :     }
     925              :     int distance;
     926              : 
     927              :     /// @brief deconstructor
     928          977 :     ~PhaseTransitionLogic() {};
     929              : 
     930              :     /// @brief get the to phase
     931              :     inline PhasePtr getToPhase(void) const {
     932       168413 :         return toPhase;
     933              :     }
     934              : 
     935              :     /// @brief get the from phase
     936              :     inline PhasePtr getFromPhase(void) const {
     937          356 :         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 2.0-1