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.core.object.DetectorType;
15 import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
16 import org.opentrafficsim.road.network.lane.object.detector.LaneDetector;
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, 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 @Override
79 public void disable()
80 {
81 Iterator<TrafficLight> it = this.redEvents.keySet().iterator();
82 while (it.hasNext())
83 {
84 TrafficLight trafficLight = it.next();
85 this.simulator.cancelEvent(this.redEvents.get(trafficLight));
86 it.remove();
87 }
88 it = this.greenEvents.keySet().iterator();
89 while (it.hasNext())
90 {
91 TrafficLight trafficLight = it.next();
92 this.simulator.cancelEvent(this.greenEvents.get(trafficLight));
93 it.remove();
94 }
95 this.enabled = false;
96 for (TrafficLight trafficLight : this.trafficLights)
97 {
98 trafficLight.setTrafficLightColor(TrafficLightColor.GREEN);
99 }
100 }
101
102
103
104
105
106 @Override
107 public void enable(final Duration cycleTime)
108 {
109 this.simulator.getLogger().always().info("Traffic light uses " + cycleTime);
110 this.cTime = cycleTime;
111 if (!this.enabled)
112 {
113 this.enabled = true;
114 for (TrafficLight trafficLight : this.trafficLights)
115 {
116 setGreen(trafficLight);
117 }
118 }
119 }
120
121
122
123
124
125 protected void setRed(final TrafficLight trafficLight)
126 {
127 this.redEvents.remove(trafficLight);
128 this.simulator.getLogger().always().info("Traffic light set to RED");
129 trafficLight.setTrafficLightColor(TrafficLightColor.RED);
130 }
131
132
133
134
135
136 protected void setGreen(final TrafficLight trafficLight)
137 {
138 this.greenEvents.remove(trafficLight);
139 this.greenStarts.put(trafficLight, this.simulator.getSimulatorAbsTime());
140 this.simulator.getLogger().always().info("Traffic light set to GREEN");
141 trafficLight.setTrafficLightColor(TrafficLightColor.GREEN);
142 }
143
144
145 private class RampMeteringDetector extends LaneDetector
146 {
147
148
149 private static final long serialVersionUID = 20190618L;
150
151
152 private final TrafficLight trafficLight;
153
154
155
156
157
158
159 RampMeteringDetector(final TrafficLight trafficLight, final DetectorType detectorType) throws NetworkException
160 {
161 super(trafficLight.getId() + "_sensor", trafficLight.getLane(), trafficLight.getLongitudinalPosition(),
162 RelativePosition.FRONT, detectorType);
163 this.trafficLight = trafficLight;
164 }
165
166 @SuppressWarnings("synthetic-access")
167 @Override
168 protected void triggerResponse(final LaneBasedGtu gtu)
169 {
170 if (CycleTimeLightController.this.enabled && this.trafficLight.getTrafficLightColor().isGreen())
171 {
172 try
173 {
174
175 Time minRedTime = CycleTimeLightController.this.simulator.getSimulatorAbsTime().plus(MIN_RED_TIME);
176 Time cycleRedTime = CycleTimeLightController.this.greenStarts.get(this.trafficLight)
177 .plus(CycleTimeLightController.this.cTime);
178 Time green;
179 if (minRedTime.ge(cycleRedTime))
180 {
181 getSimulator().getLogger().always().info("Traffic light set to RED");
182 this.trafficLight.setTrafficLightColor(TrafficLightColor.RED);
183 green = minRedTime;
184 }
185 else
186 {
187 getSimulator().getLogger().always().info("Traffic light set to YELLOW (RED over 'MIN_RED_TIME')");
188 this.trafficLight.setTrafficLightColor(TrafficLightColor.YELLOW);
189 CycleTimeLightController.this.redEvents.put(this.trafficLight,
190 CycleTimeLightController.this.simulator.scheduleEventRel(MIN_RED_TIME,
191 CycleTimeLightController.this, "setRed", new Object[] {this.trafficLight}));
192 green = cycleRedTime;
193 }
194 CycleTimeLightController.this.greenEvents.put(this.trafficLight,
195 CycleTimeLightController.this.simulator.scheduleEventAbsTime(green, CycleTimeLightController.this,
196 "setGreen", new Object[] {this.trafficLight}));
197 }
198 catch (SimRuntimeException exception)
199 {
200 throw new RuntimeException(exception);
201 }
202 }
203 }
204
205 }
206
207 }