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 }