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