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