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