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