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  
24  /**
25   * Controller using a cycle time.
26   * <p>
27   * Copyright (c) 2013-2022 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
28   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
29   * <p>
30   * @version $Revision$, $LastChangedDate$, by $Author$, initial version 12 jun. 2019 <br>
31   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
32   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
33   * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
34   */
35  public class CycleTimeLightController implements RampMeteringLightController
36  {
37  
38      /** Minimum red duration. */
39      private static final Duration MIN_RED_TIME = Duration.instantiateSI(2.0);
40  
41      /** Whether the controller is enabled. */
42      private boolean enabled = false;
43  
44      /** Time when red phase was started. */
45      private Map<TrafficLight, Time> greenStarts = new LinkedHashMap<>();
46  
47      /** Cycle time. */
48      private Duration cTime;
49  
50      /** Simulator. */
51      private final OTSSimulatorInterface simulator;
52  
53      /** Traffic lights. */
54      private final List<TrafficLight> trafficLights;
55  
56      /** Scheduled red event. */
57      private Map<TrafficLight, SimEventInterface<Duration>> redEvents = new LinkedHashMap<>();
58  
59      /** Scheduled green event. */
60      private Map<TrafficLight, SimEventInterface<Duration>> greenEvents = new LinkedHashMap<>();
61  
62      /**
63       * @param simulator OTSSimulatorInterface; simulator
64       * @param trafficLights List&lt;TrafficLight&gt;; traffic lights
65       * @param compatible Compatible; GTU types that trigger the detector, and hence the light to red
66       */
67      public CycleTimeLightController(final OTSSimulatorInterface simulator, final List<TrafficLight> trafficLights,
68              final Compatible compatible)
69      {
70          this.simulator = simulator;
71          this.trafficLights = trafficLights;
72          for (TrafficLight trafficLight : trafficLights)
73          {
74              Try.execute(() -> new RampMeteringSensor(trafficLight, simulator, compatible),
75                      "Unexpected exception while creating a detector with a ramp metering traffic light.");
76              this.greenStarts.put(trafficLight, Time.instantiateSI(Double.NEGATIVE_INFINITY));
77          }
78      }
79  
80      /** {@inheritDoc} */
81      @Override
82      public void disable()
83      {
84          Iterator<TrafficLight> it = this.redEvents.keySet().iterator();
85          while (it.hasNext())
86          {
87              TrafficLight trafficLight = it.next();
88              this.simulator.cancelEvent(this.redEvents.get(trafficLight));
89              it.remove();
90          }
91          it = this.greenEvents.keySet().iterator();
92          while (it.hasNext())
93          {
94              TrafficLight trafficLight = it.next();
95              this.simulator.cancelEvent(this.greenEvents.get(trafficLight));
96              it.remove();
97          }
98          this.enabled = false;
99          for (TrafficLight trafficLight : this.trafficLights)
100         {
101             trafficLight.setTrafficLightColor(TrafficLightColor.GREEN);
102         }
103     }
104 
105     /**
106      * Starts the cycle.
107      * @param cycleTime Duration; cycle time
108      */
109     @Override
110     public void enable(final Duration cycleTime)
111     {
112         this.simulator.getLogger().always().info("Traffic light uses " + cycleTime);
113         this.cTime = cycleTime;
114         if (!this.enabled)
115         {
116             this.enabled = true;
117             for (TrafficLight trafficLight : this.trafficLights)
118             {
119                 setGreen(trafficLight);
120             }
121         }
122     }
123 
124     /**
125      * Sets the traffic light to red. Can be scheduled.
126      * @param trafficLight TrafficLight; traffic light
127      */
128     protected void setRed(final TrafficLight trafficLight)
129     {
130         this.redEvents.remove(trafficLight);
131         this.simulator.getLogger().always().info("Traffic light set to RED");
132         trafficLight.setTrafficLightColor(TrafficLightColor.RED);
133     }
134 
135     /**
136      * Sets the traffic light to green. Can be scheduled and remembers the green time.
137      * @param trafficLight TrafficLight; traffic light
138      */
139     protected void setGreen(final TrafficLight trafficLight)
140     {
141         this.greenEvents.remove(trafficLight);
142         this.greenStarts.put(trafficLight, this.simulator.getSimulatorAbsTime());
143         this.simulator.getLogger().always().info("Traffic light set to GREEN");
144         trafficLight.setTrafficLightColor(TrafficLightColor.GREEN);
145     }
146 
147     /** Ramp metering sensor. */
148     private class RampMeteringSensor extends AbstractSensor
149     {
150 
151         /** */
152         private static final long serialVersionUID = 20190618L;
153 
154         /** The traffic light. */
155         private final TrafficLight trafficLight;
156 
157         /**
158          * @param trafficLight TrafficLight; traffic light
159          * @param simulator TimeDoubleUnit; simulator
160          * @param detectedGTUTypes Compatible; GTU types
161          * @throws NetworkException when the position on the lane is out of bounds
162          */
163         RampMeteringSensor(final TrafficLight trafficLight, final OTSSimulatorInterface simulator,
164                 final Compatible detectedGTUTypes) throws NetworkException
165         {
166             super(trafficLight.getId() + "_sensor", trafficLight.getLane(), trafficLight.getLongitudinalPosition(),
167                     RelativePosition.FRONT, simulator, detectedGTUTypes);
168             this.trafficLight = trafficLight;
169         }
170 
171         /** {@inheritDoc} */
172         @SuppressWarnings("synthetic-access")
173         @Override
174         protected void triggerResponse(final LaneBasedGTU gtu)
175         {
176             if (CycleTimeLightController.this.enabled && this.trafficLight.getTrafficLightColor().isGreen())
177             {
178                 try
179                 {
180                     // schedule green
181                     Time minRedTime = CycleTimeLightController.this.simulator.getSimulatorAbsTime().plus(MIN_RED_TIME);
182                     Time cycleRedTime = CycleTimeLightController.this.greenStarts.get(this.trafficLight)
183                             .plus(CycleTimeLightController.this.cTime);
184                     Time green;
185                     if (minRedTime.ge(cycleRedTime))
186                     {
187                         getSimulator().getLogger().always().info("Traffic light set to RED");
188                         this.trafficLight.setTrafficLightColor(TrafficLightColor.RED);
189                         green = minRedTime;
190                     }
191                     else
192                     {
193                         getSimulator().getLogger().always().info("Traffic light set to YELLOW (RED over 'MIN_RED_TIME')");
194                         this.trafficLight.setTrafficLightColor(TrafficLightColor.YELLOW);
195                         CycleTimeLightController.this.redEvents.put(this.trafficLight,
196                                 CycleTimeLightController.this.simulator.scheduleEventRel(MIN_RED_TIME, this,
197                                         CycleTimeLightController.this, "setRed", new Object[] {this.trafficLight}));
198                         green = cycleRedTime;
199                     }
200                     CycleTimeLightController.this.greenEvents.put(this.trafficLight,
201                             CycleTimeLightController.this.simulator.scheduleEventAbsTime(green, this,
202                                     CycleTimeLightController.this, "setGreen", new Object[] {this.trafficLight}));
203                 }
204                 catch (SimRuntimeException exception)
205                 {
206                     throw new RuntimeException(exception);
207                 }
208             }
209         }
210 
211         /** {@inheritDoc} */
212         @Override
213         public AbstractSensor clone(final CrossSectionElement newCSE, final OTSSimulatorInterface newSimulator)
214                 throws NetworkException
215         {
216             return null; // TODO: should be cloned as part of the ramp metering
217         }
218 
219     }
220 
221 }