View Javadoc
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   * Controller using a cycle time.
29   * <p>
30   * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
31   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
32   * <p>
33   * @version $Revision$, $LastChangedDate$, by $Author$, initial version 12 jun. 2019 <br>
34   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
35   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
36   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
37   */
38  public class CycleTimeLightController implements RampMeteringLightController
39  {
40  
41      /** Minimum red duration. */
42      private static final Duration MIN_RED_TIME = Duration.instantiateSI(2.0);
43  
44      /** Whether the controller is enabled. */
45      private boolean enabled = false;
46  
47      /** Time when red phase was started. */
48      private Map<TrafficLight, Time> greenStarts = new LinkedHashMap<>();
49  
50      /** Cycle time. */
51      private Duration cTime;
52  
53      /** Simulator. */
54      private final OTSSimulatorInterface simulator;
55  
56      /** Traffic lights. */
57      private final List<TrafficLight> trafficLights;
58  
59      /** Scheduled red event. */
60      private Map<TrafficLight, SimEventInterface<SimTimeDoubleUnit>> redEvents = new LinkedHashMap<>();
61  
62      /** Scheduled green event. */
63      private Map<TrafficLight, SimEventInterface<SimTimeDoubleUnit>> greenEvents = new LinkedHashMap<>();
64  
65      /**
66       * @param simulator OTSSimulatorInterface; simulator
67       * @param trafficLights List&lt;TrafficLight&gt;; traffic lights
68       * @param compatible Compatible; GTU types that trigger the detector, and hence the light to red
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      /** {@inheritDoc} */
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      * Starts the cycle.
110      * @param cycleTime Duration; cycle time
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      * Sets the traffic light to red. Can be scheduled.
129      * @param trafficLight TrafficLight; traffic light
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      * Sets the traffic light to green. Can be scheduled and remembers the green time.
140      * @param trafficLight TrafficLight; traffic light
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     /** Ramp metering sensor. */
151     private class RampMeteringSensor extends AbstractSensor
152     {
153 
154         /** */
155         private static final long serialVersionUID = 20190618L;
156 
157         /** The traffic light. */
158         private final TrafficLight trafficLight;
159 
160         /**
161          * @param trafficLight TrafficLight; traffic light
162          * @param simulator TimeDoubleUnit; simulator
163          * @param detectedGTUTypes Compatible; GTU types
164          * @throws NetworkException when the position on the lane is out of bounds
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         /** {@inheritDoc} */
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                     // schedule green
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         /** {@inheritDoc} */
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; // TODO: should be cloned as part of the ramp metering
221         }
222 
223     }
224 
225 }