LCOV - code coverage report
Current view: top level - src/microsim/traffic_lights - MSDelayBasedTrafficLightLogic.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 77.4 % 93 72
Test Date: 2024-11-22 15:46:21 Functions: 60.0 % 10 6

            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    MSDelayBasedTrafficLightLogic.cpp
      15              : /// @author  Leonhard Luecken
      16              : /// @date    Feb 2017
      17              : ///
      18              : // An actuated traffic light logic based on time delay of approaching vehicles
      19              : /****************************************************************************/
      20              : #include <config.h>
      21              : 
      22              : #include <cassert>
      23              : #include <vector>
      24              : #include <utils/common/FileHelpers.h>
      25              : #include <utils/common/StringUtils.h>
      26              : #include <microsim/MSGlobals.h>
      27              : #include <microsim/MSNet.h>
      28              : #include <microsim/output/MSDetectorControl.h>
      29              : #include <microsim/MSLane.h>
      30              : #include <netload/NLDetectorBuilder.h>
      31              : #include "MSDelayBasedTrafficLightLogic.h"
      32              : 
      33              : #define INVALID_POSITION std::numeric_limits<double>::max()
      34              : 
      35              : // ===========================================================================
      36              : // parameter defaults definitions
      37              : // ===========================================================================
      38              : 
      39              : //#define DEBUG_TIMELOSS_CONTROL
      40              : 
      41              : // ===========================================================================
      42              : // method definitions
      43              : // ===========================================================================
      44          102 : MSDelayBasedTrafficLightLogic::MSDelayBasedTrafficLightLogic(MSTLLogicControl& tlcontrol,
      45              :         const std::string& id, const std::string& programID,
      46              :         const SUMOTime offset,
      47              :         const Phases& phases,
      48              :         int step, SUMOTime delay,
      49              :         const Parameterised::Map& parameter,
      50          102 :         const std::string& basePath) :
      51          102 :     MSSimpleTrafficLightLogic(tlcontrol, id, programID, offset, TrafficLightType::DELAYBASED, phases, step, delay, parameter) {
      52              : #ifdef DEBUG_TIMELOSS_CONTROL
      53              :     std::cout << "Building delay based tls logic '" << id << "'" << std::endl;
      54              : #endif
      55          204 :     myShowDetectors = StringUtils::toBool(getParameter("show-detectors", "false"));
      56          204 :     myDetectionRange = StringUtils::toDouble(getParameter("detectorRange", toString(OptionsCont::getOptions().getFloat("tls.delay_based.detector-range"))));
      57          204 :     myTimeLossThreshold = StringUtils::toDouble(getParameter("minTimeloss", "1.0"));
      58          204 :     myFile = FileHelpers::checkForRelativity(getParameter("file", "NUL"), basePath);
      59          306 :     myFreq = TIME2STEPS(StringUtils::toDouble(getParameter("freq", "300")));
      60          204 :     myVehicleTypes = getParameter("vTypes", "");
      61          204 :     myExtendMaxDur = StringUtils::toBool(getParameter("extendMaxDur", "false"));
      62              : #ifdef DEBUG_TIMELOSS_CONTROL
      63              :     std::cout << "show-detectors: " << myShowDetectors
      64              :               << " detectorRange: " << myDetectionRange
      65              :               << " minTimeLoss: " << myTimeLossThreshold
      66              :               << " file: " << myFile
      67              :               << " freq: " << myFreq
      68              :               << " vTypes: " << myVehicleTypes
      69              :               << std::endl;
      70              : #endif
      71          102 : }
      72              : 
      73              : 
      74              : void
      75          102 : MSDelayBasedTrafficLightLogic::init(NLDetectorBuilder& nb) {
      76          102 :     MSTrafficLightLogic::init(nb);
      77              :     assert(myLanes.size() > 0);
      78              :     LaneVectorVector::const_iterator i2;
      79              :     LaneVector::const_iterator i;
      80              :     // build the E2 detectors
      81         1808 :     for (i2 = myLanes.begin(); i2 != myLanes.end(); ++i2) {
      82              :         const LaneVector& lanes = *i2;
      83         3420 :         for (i = lanes.begin(); i != lanes.end(); i++) {
      84         1714 :             MSLane* lane = (*i);
      85         1714 :             if (noVehicles(lane->getPermissions())) {
      86              :                 // do not build detectors on green verges or sidewalks
      87            8 :                 continue;
      88              :             }
      89              :             // Build the detectors and register them at the detector control
      90         1706 :             if (myLaneDetectors.find(lane) == myLaneDetectors.end()) {
      91              :                 MSE2Collector* det = nullptr;
      92         1406 :                 const std::string customID = getParameter(lane->getID());
      93          703 :                 if (customID != "") {
      94            2 :                     det = dynamic_cast<MSE2Collector*>(MSNet::getInstance()->getDetectorControl().getTypedDetectors(SUMO_TAG_LANE_AREA_DETECTOR).get(customID));
      95            1 :                     if (det == nullptr) {
      96            0 :                         WRITE_ERRORF(TL("Unknown laneAreaDetector '%' given as custom detector for delay_based tlLogic '%', program '%."), customID, getID(), getProgramID());
      97              :                         continue;
      98              :                     }
      99            1 :                     det->setVisible(myShowDetectors);
     100              :                 } else {
     101              :                     // check whether the lane (or unamibiguous lane sequence) is long enough and avoid overlapping detectors
     102          702 :                     double length = lane->getLength();
     103              :                     MSLane* firstLane = lane;
     104         1283 :                     while (length < myDetectionRange && firstLane->getIncomingLanes().size() == 1
     105         1280 :                             && firstLane->getIncomingLanes().front().viaLink->getCorrespondingEntryLink()->getTLLogic() == nullptr) {
     106          230 :                         firstLane = firstLane->getLogicalPredecessorLane();
     107          230 :                         if (firstLane->getLinkCont().size() > 1) {
     108              :                             break;
     109              :                         }
     110          224 :                         length += firstLane->getLength();
     111              :                     }
     112          702 :                     length = MIN2(length, myDetectionRange);
     113              : 
     114          702 :                     std::string id = "TLS" + myID + "_" + myProgramID + "_E2CollectorOn_" + lane->getID();
     115         1404 :                     det = nb.createE2Detector(id, DU_TL_CONTROL, lane, INVALID_POSITION, lane->getLength(), length, TIME2STEPS(1.0), 5.0 / 3.6, 10.0, "", myVehicleTypes, "", (int)PersonMode::NONE, myShowDetectors);
     116          702 :                     MSNet::getInstance()->getDetectorControl().add(SUMO_TAG_LANE_AREA_DETECTOR, det, myFile, myFreq);
     117              :                 }
     118          703 :                 myLaneDetectors[lane] = det;
     119              :             }
     120              :         }
     121              :     }
     122          102 : }
     123              : 
     124              : 
     125              : 
     126          306 : MSDelayBasedTrafficLightLogic::~MSDelayBasedTrafficLightLogic() { }
     127              : 
     128              : // ------------ Switching and setting current rows
     129              : 
     130              : 
     131              : SUMOTime
     132       108169 : MSDelayBasedTrafficLightLogic::proposeProlongation(const SUMOTime actDuration, const SUMOTime maxDuration, bool& othersEmpty) {
     133              : #ifdef DEBUG_TIMELOSS_CONTROL
     134              :     std::cout << "\n" << SIMTIME << " MSDelayBasedTrafficLightLogic::proposeProlongation() for TLS '" << this->getID() << "' (current phase = " << myStep << ")" << std::endl;
     135              : #endif
     136              :     SUMOTime prolongation = 0;
     137       108169 :     const std::string& state = getCurrentPhaseDef().getState();
     138              :     // iterate over green lanes, eventually increase the proposed prolongationTime to the estimated passing time for each lane.
     139      1835162 :     for (int i = 0; i < (int) state.size(); i++)  {
     140              :         // this lane index corresponds to a non-green time
     141      1727569 :         bool igreen = state[i] == LINKSTATE_TL_GREEN_MAJOR || state[i] == LINKSTATE_TL_GREEN_MINOR;
     142      3306521 :         for (const MSLane* const lane : getLanesAt(i)) {
     143              :             std::map<const MSLane*, MSE2Collector*>::iterator it = myLaneDetectors.find(lane);
     144      1729120 :             if (it == myLaneDetectors.end()) {
     145              : #ifdef DEBUG_TIMELOSS_CONTROL
     146              :                 // no detector for this lane!? maybe noVehicles allowed
     147              :                 std::cout << "no detector on lane '" << lane->getID() << std::endl;
     148              : #endif
     149        25648 :                 continue;
     150              :             }
     151      1703472 :             const std::vector<MSE2Collector::VehicleInfo*> vehInfos = it->second->getCurrentVehicles();
     152              : #ifdef DEBUG_TIMELOSS_CONTROL
     153              :             int nrVehs = 0; // count vehicles on detector
     154              : #endif
     155      1703472 :             if (igreen) {
     156              :                 // green phase
     157      1606860 :                 for (const MSE2Collector::VehicleInfo* const iv : vehInfos) {
     158       754686 :                     if (iv->accumulatedTimeLoss > myTimeLossThreshold && iv->distToDetectorEnd > 0) {
     159       303403 :                         const SUMOTime estimatedTimeToJunction = TIME2STEPS((iv->distToDetectorEnd) / lane->getSpeedLimit());
     160       303403 :                         if (actDuration + estimatedTimeToJunction  <= maxDuration && getLatest() > 0) {
     161              :                             // only prolong if vehicle has a chance to pass until max duration is reached
     162              :                             prolongation = MAX2(prolongation, estimatedTimeToJunction);
     163              :                         }
     164              : #ifdef DEBUG_TIMELOSS_CONTROL
     165              :                         nrVehs++;
     166              : #endif
     167              : 
     168              : #ifdef DEBUG_TIMELOSS_CONTROL
     169              :                         std::cout << "vehicle '" << iv->id << "' with accumulated timeloss: " << iv->accumulatedTimeLoss
     170              :                                   << "\nestimated passing time: " << estimatedTimeToJunction << std::endl;
     171              :                     } else {
     172              :                         std::string reason = iv->accumulatedTimeLoss <= myTimeLossThreshold ? " (time loss below threshold)" : " (front already left detector)";
     173              :                         std::cout << "disregarded: (vehicle '" << iv->id << "' with accumulated timeloss " << iv->accumulatedTimeLoss << ")" << reason << std::endl;
     174              : #endif
     175              :                     }
     176              :                 }
     177              :             } else {
     178              :                 // non-green phase
     179       851298 :                 if (vehInfos.size() > 0) {
     180              :                     // here is a car on a non-green approach
     181       150168 :                     othersEmpty = false;
     182       150168 :                     if (actDuration >= getCurrentPhaseDef().maxDuration) {
     183              : #ifdef DEBUG_TIMELOSS_CONTROL
     184              :                         std::cout << "Actual duration exceeds maxDuration and a vehicle is on concurrent approach: " << nrVehs << std::endl;
     185              : #endif
     186              :                         // don't prolong
     187              :                         return 0;
     188              :                     }
     189              :                     break;
     190              :                 }
     191              : #ifdef DEBUG_TIMELOSS_CONTROL
     192              :                 std::cout << "Number of current vehicles on detector: " << nrVehs << std::endl;
     193              : #endif
     194              :             }
     195      1703472 :         }
     196              :     }
     197              : #ifdef DEBUG_TIMELOSS_CONTROL
     198              :     std::cout << "Proposed prolongation (maximal estimated passing time): " << prolongation << std::endl; // debug
     199              : #endif
     200              :     return prolongation;
     201              : }
     202              : 
     203              : 
     204              : SUMOTime
     205       114071 : MSDelayBasedTrafficLightLogic::trySwitch() {
     206              :     /* check if the actual phase should be prolonged */
     207       114071 :     const MSPhaseDefinition& currentPhase = getCurrentPhaseDef();
     208              :     // time since last switch
     209       114071 :     const SUMOTime actDuration = MSNet::getInstance()->getCurrentTimeStep() - currentPhase.myLastSwitch;
     210              : 
     211              : #ifdef DEBUG_TIMELOSS_CONTROL
     212              :     std::cout << "last switch = " << currentPhase.myLastSwitch
     213              :               << "\nactDuration = " << actDuration
     214              :               << "\nmaxDuration = " << currentPhase.maxDuration
     215              :               << std::endl;
     216              : #endif
     217              : 
     218              :     // flag whether to prolong or not
     219       114071 :     if (currentPhase.isGreenPhase() && !MSGlobals::gUseMesoSim) {
     220       108169 :         bool othersEmpty = true; // whether no vehicles are present on concurrent approaches
     221       108169 :         SUMOTime proposedProlongation = proposeProlongation(actDuration, currentPhase.maxDuration, othersEmpty);
     222              : 
     223              : #ifdef DEBUG_TIMELOSS_CONTROL
     224              :         std::cout << "othersEmpty = " << othersEmpty
     225              :                   << std::endl;
     226              : #endif
     227              : 
     228              :         // assure minimal duration
     229       108169 :         proposedProlongation = MAX3(SUMOTime(0), proposedProlongation, currentPhase.minDuration - actDuration);
     230       108169 :         if (othersEmpty) {
     231              :             // prolong by one second if no vehicles on other approaches
     232              :             proposedProlongation = MAX2(proposedProlongation, TIME2STEPS(1.));
     233              :         } else {
     234              :             // vehicles are present on other approaches -> prolong no further than the max green time
     235        38022 :             proposedProlongation = MIN2(proposedProlongation, MAX2(SUMOTime(0), currentPhase.maxDuration - actDuration));
     236              :         }
     237       108169 :         if (!myExtendMaxDur) {
     238       107620 :             proposedProlongation = MIN2(proposedProlongation, MAX2(SUMOTime(0), currentPhase.maxDuration - actDuration));
     239              :         }
     240              : 
     241              : #ifdef DEBUG_TIMELOSS_CONTROL
     242              :         std::cout << "Proposed prolongation = " << proposedProlongation << std::endl;
     243              : #endif
     244              : 
     245       108169 :         if (proposedProlongation > 0) {
     246              :             // check again after the prolonged period (must be positive...)
     247              :             // XXX: Can it be harmful not to return a duration of integer seconds?
     248       101228 :             return proposedProlongation;
     249              :         }
     250              :     }
     251              :     // Don't prolong... switch to the next phase
     252        12843 :     const SUMOTime prevStart = myPhases[myStep]->myLastSwitch;
     253        12843 :     myStep = (myStep + 1) % (int)myPhases.size();
     254        12843 :     myPhases[myStep]->myLastSwitch = SIMSTEP;
     255              :     MSPhaseDefinition* newPhase = myPhases[myStep];
     256              :     //stores the time the phase started
     257        12843 :     newPhase->myLastSwitch = MSNet::getInstance()->getCurrentTimeStep();
     258              :     // set the next event
     259        12843 :     return MAX2(newPhase->minDuration, getEarliest(prevStart));
     260              : }
     261              : 
     262              : void
     263            0 : MSDelayBasedTrafficLightLogic::setShowDetectors(bool show) {
     264            0 :     myShowDetectors = show;
     265            0 :     for (auto& item : myLaneDetectors) {
     266            0 :         item.second->setVisible(myShowDetectors);
     267              :     }
     268            0 : }
     269              : 
     270              : std::map<std::string, double>
     271            0 : MSDelayBasedTrafficLightLogic::getDetectorStates() const {
     272              :     std::map<std::string, double> result;
     273            0 :     for (auto item : myLaneDetectors) {
     274            0 :         result[item.second->getID()] = item.second->getCurrentVehicleNumber();
     275              :     }
     276            0 :     return result;
     277              : }
     278              : 
     279              : double
     280            0 : MSDelayBasedTrafficLightLogic::getDetectorState(std::string laneID) const {
     281              :     double result = 0.0;
     282            0 :     for (auto item : myLaneDetectors) {
     283            0 :         if (item.first->getID() == laneID) {
     284            0 :             result = item.second->getCurrentVehicleNumber();
     285            0 :             break;
     286              :         }
     287              :     }
     288            0 :     return result;
     289              : }
     290              : 
     291              : double
     292            0 : MSDelayBasedTrafficLightLogic::getTLQueueLength(std::string laneID) const {
     293              :     double result = 0.0;
     294            0 :     for (auto item : myLaneDetectors) {
     295            0 :         if (item.first->getID() == laneID) {
     296            0 :             result = item.second->getEstimateQueueLength();
     297              :             break;
     298              :         }
     299              :     }
     300            0 :     return result;
     301              : }
     302              : 
     303              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1