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