LCOV - code coverage report
Current view: top level - src/microsim/traffic_lights - MSDelayBasedTrafficLightLogic.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 70 77 90.9 %
Date: 2024-05-19 15:37:39 Functions: 6 7 85.7 %

          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         107 : 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         107 :         const std::string& basePath) :
      51         107 :     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         107 :     myShowDetectors = StringUtils::toBool(getParameter("show-detectors", "false"));
      56         107 :     myDetectionRange = StringUtils::toDouble(getParameter("detectorRange", toString(OptionsCont::getOptions().getFloat("tls.delay_based.detector-range"))));
      57         107 :     myTimeLossThreshold = StringUtils::toDouble(getParameter("minTimeloss", "1.0"));
      58         214 :     myFile = FileHelpers::checkForRelativity(getParameter("file", "NUL"), basePath);
      59         107 :     myFreq = TIME2STEPS(StringUtils::toDouble(getParameter("freq", "300")));
      60         214 :     myVehicleTypes = getParameter("vTypes", "");
      61         107 :     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         107 : }
      72             : 
      73             : 
      74             : void
      75         107 : MSDelayBasedTrafficLightLogic::init(NLDetectorBuilder& nb) {
      76         107 :     MSTrafficLightLogic::init(nb);
      77             :     assert(myLanes.size() > 0);
      78             :     LaneVectorVector::const_iterator i2;
      79             :     LaneVector::const_iterator i;
      80             :     // build the E2 detectors
      81        1960 :     for (i2 = myLanes.begin(); i2 != myLanes.end(); ++i2) {
      82             :         const LaneVector& lanes = *i2;
      83        3722 :         for (i = lanes.begin(); i != lanes.end(); i++) {
      84        1869 :             MSLane* lane = (*i);
      85        1869 :             if (noVehicles(lane->getPermissions())) {
      86             :                 // do not build detectors on green verges or sidewalks
      87           4 :                 continue;
      88             :             }
      89             :             // Build the detectors and register them at the detector control
      90        1865 :             if (myLaneDetectors.find(lane) == myLaneDetectors.end()) {
      91             :                 MSE2Collector* det = nullptr;
      92        1650 :                 const std::string customID = getParameter(lane->getID());
      93         825 :                 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         824 :                     double length = lane->getLength();
     103             :                     MSLane* firstLane = lane;
     104        1631 :                     while (length < myDetectionRange && firstLane->getIncomingLanes().size() == 1
     105        1782 :                             && firstLane->getIncomingLanes().front().viaLink->getCorrespondingEntryLink()->getTLLogic() == nullptr) {
     106         326 :                         firstLane = firstLane->getLogicalPredecessorLane();
     107         326 :                         if (firstLane->getLinkCont().size() > 1) {
     108             :                             break;
     109             :                         }
     110         320 :                         length += firstLane->getLength();
     111             :                     }
     112         824 :                     length = MIN2(length, myDetectionRange);
     113             : 
     114        1648 :                     std::string id = "TLS" + myID + "_" + myProgramID + "_E2CollectorOn_" + lane->getID();
     115        1648 :                     det = nb.createE2Detector(id, DU_TL_CONTROL, lane, INVALID_POSITION, lane->getLength(), length, 0, 0, 0, "", myVehicleTypes, "", (int)PersonMode::NONE, myShowDetectors);
     116         824 :                     MSNet::getInstance()->getDetectorControl().add(SUMO_TAG_LANE_AREA_DETECTOR, det, myFile, myFreq);
     117             :                 }
     118         825 :                 myLaneDetectors[lane] = det;
     119             :             }
     120             :         }
     121             :     }
     122         107 : }
     123             : 
     124             : 
     125             : 
     126         321 : MSDelayBasedTrafficLightLogic::~MSDelayBasedTrafficLightLogic() { }
     127             : 
     128             : // ------------ Switching and setting current rows
     129             : 
     130             : 
     131             : SUMOTime
     132      180723 : 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      180723 :     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     3774370 :     for (int i = 0; i < (int) state.size(); i++)  {
     140             :         // this lane index corresponds to a non-green time
     141     3594807 :         bool igreen = state[i] == LINKSTATE_TL_GREEN_MAJOR || state[i] == LINKSTATE_TL_GREEN_MINOR;
     142     6719591 :         for (const MSLane* const lane : getLanesAt(i)) {
     143             :             std::map<const MSLane*, MSE2Collector*>::iterator it = myLaneDetectors.find(lane);
     144     3595124 :             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           0 :                 continue;
     150             :             }
     151     3595124 :             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     3595124 :             if (igreen) {
     156             :                 // green phase
     157     3240473 :                 for (const MSE2Collector::VehicleInfo* const iv : vehInfos) {
     158     1443897 :                     if (iv->accumulatedTimeLoss > myTimeLossThreshold && iv->distToDetectorEnd > 0) {
     159      991862 :                         const SUMOTime estimatedTimeToJunction = TIME2STEPS((iv->distToDetectorEnd) / lane->getSpeedLimit());
     160      991862 :                         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     1798548 :                 if (vehInfos.size() > 0) {
     180             :                     // here is a car on a non-green approach
     181      470340 :                     othersEmpty = false;
     182      470340 :                     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             :         }
     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      188257 : MSDelayBasedTrafficLightLogic::trySwitch() {
     206             :     /* check if the actual phase should be prolonged */
     207      188257 :     const MSPhaseDefinition& currentPhase = getCurrentPhaseDef();
     208             :     // time since last switch
     209      188257 :     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      188257 :     if (currentPhase.isGreenPhase() && !MSGlobals::gUseMesoSim) {
     220      180723 :         bool othersEmpty = true; // whether no vehicles are present on concurrent approaches
     221      180723 :         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      180723 :         proposedProlongation = MAX3(SUMOTime(0), proposedProlongation, currentPhase.minDuration - actDuration);
     230      180723 :         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      120177 :             proposedProlongation = MIN2(proposedProlongation, MAX2(SUMOTime(0), currentPhase.maxDuration - actDuration));
     236             :         }
     237      180723 :         if (!myExtendMaxDur) {
     238      180174 :             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      180723 :         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      172910 :             return proposedProlongation;
     249             :         }
     250             :     }
     251             :     // Don't prolong... switch to the next phase
     252       15347 :     const SUMOTime prevStart = myPhases[myStep]->myLastSwitch;
     253       15347 :     myStep = (myStep + 1) % (int)myPhases.size();
     254       15347 :     myPhases[myStep]->myLastSwitch = SIMSTEP;
     255             :     MSPhaseDefinition* newPhase = myPhases[myStep];
     256             :     //stores the time the phase started
     257       15347 :     newPhase->myLastSwitch = MSNet::getInstance()->getCurrentTimeStep();
     258             :     // set the next event
     259       15347 :     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             : 
     271             : 
     272             : /****************************************************************************/

Generated by: LCOV version 1.14