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 : /****************************************************************************/
|