1 package org.opentrafficsim.road.network.control.rampmetering;
2
3 import java.util.Iterator;
4 import java.util.LinkedHashMap;
5 import java.util.List;
6 import java.util.Map;
7
8 import org.djunits.value.vdouble.scalar.Duration;
9 import org.djutils.exceptions.Try;
10 import org.opentrafficsim.base.OtsRuntimeException;
11 import org.opentrafficsim.base.logger.Logger;
12 import org.opentrafficsim.core.dsol.OtsSimulatorInterface;
13 import org.opentrafficsim.core.gtu.RelativePosition;
14 import org.opentrafficsim.core.network.NetworkException;
15 import org.opentrafficsim.core.object.DetectorType;
16 import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
17 import org.opentrafficsim.road.network.lane.object.detector.LaneDetector;
18 import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLight;
19 import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLightColor;
20
21 import nl.tudelft.simulation.dsol.SimRuntimeException;
22 import nl.tudelft.simulation.dsol.formalisms.eventscheduling.SimEventInterface;
23
24
25
26
27
28
29
30
31
32
33
34 public class CycleTimeLightController implements RampMeteringLightController
35 {
36
37
38 private static final Duration MIN_RED_TIME = Duration.ofSI(2.0);
39
40
41 private boolean enabled = false;
42
43
44 private Map<TrafficLight, Duration> greenStarts = new LinkedHashMap<>();
45
46
47 private Duration cTime;
48
49
50 private final OtsSimulatorInterface simulator;
51
52
53 private final List<TrafficLight> trafficLights;
54
55
56 private Map<TrafficLight, SimEventInterface<Duration>> redEvents = new LinkedHashMap<>();
57
58
59 private Map<TrafficLight, SimEventInterface<Duration>> greenEvents = new LinkedHashMap<>();
60
61
62
63
64
65
66
67 public CycleTimeLightController(final OtsSimulatorInterface simulator, final List<TrafficLight> trafficLights,
68 final DetectorType detectorType)
69 {
70 this.simulator = simulator;
71 this.trafficLights = trafficLights;
72 for (TrafficLight trafficLight : trafficLights)
73 {
74 Try.execute(() -> new RampMeteringDetector(trafficLight, detectorType),
75 "Unexpected exception while creating a detector with a ramp metering traffic light.");
76 this.greenStarts.put(trafficLight, Duration.NEGATIVE_INFINITY);
77 }
78 }
79
80 @Override
81 public void disable()
82 {
83 Iterator<TrafficLight> it = this.redEvents.keySet().iterator();
84 while (it.hasNext())
85 {
86 TrafficLight trafficLight = it.next();
87 this.simulator.cancelEvent(this.redEvents.get(trafficLight));
88 it.remove();
89 }
90 it = this.greenEvents.keySet().iterator();
91 while (it.hasNext())
92 {
93 TrafficLight trafficLight = it.next();
94 this.simulator.cancelEvent(this.greenEvents.get(trafficLight));
95 it.remove();
96 }
97 this.enabled = false;
98 for (TrafficLight trafficLight : this.trafficLights)
99 {
100 trafficLight.setTrafficLightColor(TrafficLightColor.GREEN);
101 }
102 }
103
104
105
106
107
108 @Override
109 public void enable(final Duration cycleTime)
110 {
111 Logger.ots().info("Traffic light uses " + cycleTime);
112 this.cTime = cycleTime;
113 if (!this.enabled)
114 {
115 this.enabled = true;
116 for (TrafficLight trafficLight : this.trafficLights)
117 {
118 setGreen(trafficLight);
119 }
120 }
121 }
122
123
124
125
126
127 protected void setRed(final TrafficLight trafficLight)
128 {
129 this.redEvents.remove(trafficLight);
130 Logger.ots().info("Traffic light set to RED");
131 trafficLight.setTrafficLightColor(TrafficLightColor.RED);
132 }
133
134
135
136
137
138 protected void setGreen(final TrafficLight trafficLight)
139 {
140 this.greenEvents.remove(trafficLight);
141 this.greenStarts.put(trafficLight, this.simulator.getSimulatorTime());
142 Logger.ots().info("Traffic light set to GREEN");
143 trafficLight.setTrafficLightColor(TrafficLightColor.GREEN);
144 }
145
146
147 private class RampMeteringDetector extends LaneDetector
148 {
149
150
151 private final TrafficLight trafficLight;
152
153
154
155
156
157
158 RampMeteringDetector(final TrafficLight trafficLight, final DetectorType detectorType) throws NetworkException
159 {
160 super(trafficLight.getId() + "_sensor", trafficLight.getLane(), trafficLight.getLongitudinalPosition(),
161 RelativePosition.FRONT, detectorType);
162 this.trafficLight = trafficLight;
163 }
164
165 @SuppressWarnings("synthetic-access")
166 @Override
167 protected void triggerResponse(final LaneBasedGtu gtu)
168 {
169 if (CycleTimeLightController.this.enabled && this.trafficLight.getTrafficLightColor().isGreen())
170 {
171 try
172 {
173
174 Duration minRedTime = CycleTimeLightController.this.simulator.getSimulatorTime().plus(MIN_RED_TIME);
175 Duration cycleRedTime = CycleTimeLightController.this.greenStarts.get(this.trafficLight)
176 .plus(CycleTimeLightController.this.cTime);
177 Duration green;
178 if (minRedTime.ge(cycleRedTime))
179 {
180 Logger.ots().info("Traffic light set to RED");
181 this.trafficLight.setTrafficLightColor(TrafficLightColor.RED);
182 green = minRedTime;
183 }
184 else
185 {
186 Logger.ots().info("Traffic light set to YELLOW (RED over 'MIN_RED_TIME')");
187 this.trafficLight.setTrafficLightColor(TrafficLightColor.YELLOW);
188 CycleTimeLightController.this.redEvents.put(this.trafficLight, CycleTimeLightController.this.simulator
189 .scheduleEventRel(MIN_RED_TIME, () -> CycleTimeLightController.this.setRed(this.trafficLight)));
190 green = cycleRedTime;
191 }
192 CycleTimeLightController.this.greenEvents.put(this.trafficLight,
193 CycleTimeLightController.this.simulator.scheduleEventAbs(Duration.ofSI(green.si),
194 () -> CycleTimeLightController.this.setGreen(this.trafficLight)));
195 }
196 catch (SimRuntimeException exception)
197 {
198 throw new OtsRuntimeException(exception);
199 }
200 }
201 }
202
203 }
204
205 }