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.core.object.DetectorType;
15  import org.opentrafficsim.road.gtu.lane.LaneBasedGtu;
16  import org.opentrafficsim.road.network.lane.object.detector.LaneDetector;
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://github.com/peter-knoppers">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 simulator
62       * @param trafficLights traffic lights
63       * @param 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, 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      @Override
79      public void disable()
80      {
81          Iterator<TrafficLight> it = this.redEvents.keySet().iterator();
82          while (it.hasNext())
83          {
84              TrafficLight trafficLight = it.next();
85              this.simulator.cancelEvent(this.redEvents.get(trafficLight));
86              it.remove();
87          }
88          it = this.greenEvents.keySet().iterator();
89          while (it.hasNext())
90          {
91              TrafficLight trafficLight = it.next();
92              this.simulator.cancelEvent(this.greenEvents.get(trafficLight));
93              it.remove();
94          }
95          this.enabled = false;
96          for (TrafficLight trafficLight : this.trafficLights)
97          {
98              trafficLight.setTrafficLightColor(TrafficLightColor.GREEN);
99          }
100     }
101 
102     /**
103      * Starts the cycle.
104      * @param cycleTime cycle time
105      */
106     @Override
107     public void enable(final Duration cycleTime)
108     {
109         this.simulator.getLogger().always().info("Traffic light uses " + cycleTime);
110         this.cTime = cycleTime;
111         if (!this.enabled)
112         {
113             this.enabled = true;
114             for (TrafficLight trafficLight : this.trafficLights)
115             {
116                 setGreen(trafficLight);
117             }
118         }
119     }
120 
121     /**
122      * Sets the traffic light to red. Can be scheduled.
123      * @param trafficLight traffic light
124      */
125     protected void setRed(final TrafficLight trafficLight)
126     {
127         this.redEvents.remove(trafficLight);
128         this.simulator.getLogger().always().info("Traffic light set to RED");
129         trafficLight.setTrafficLightColor(TrafficLightColor.RED);
130     }
131 
132     /**
133      * Sets the traffic light to green. Can be scheduled and remembers the green time.
134      * @param trafficLight traffic light
135      */
136     protected void setGreen(final TrafficLight trafficLight)
137     {
138         this.greenEvents.remove(trafficLight);
139         this.greenStarts.put(trafficLight, this.simulator.getSimulatorAbsTime());
140         this.simulator.getLogger().always().info("Traffic light set to GREEN");
141         trafficLight.setTrafficLightColor(TrafficLightColor.GREEN);
142     }
143 
144     /** Ramp metering sensor. */
145     private class RampMeteringDetector extends LaneDetector
146     {
147 
148         /** */
149         private static final long serialVersionUID = 20190618L;
150 
151         /** The traffic light. */
152         private final TrafficLight trafficLight;
153 
154         /**
155          * @param trafficLight traffic light
156          * @param detectorType detector type.
157          * @throws NetworkException when the position on the lane is out of bounds
158          */
159         RampMeteringDetector(final TrafficLight trafficLight, final DetectorType detectorType) throws NetworkException
160         {
161             super(trafficLight.getId() + "_sensor", trafficLight.getLane(), trafficLight.getLongitudinalPosition(),
162                     RelativePosition.FRONT, detectorType);
163             this.trafficLight = trafficLight;
164         }
165 
166         @SuppressWarnings("synthetic-access")
167         @Override
168         protected void triggerResponse(final LaneBasedGtu gtu)
169         {
170             if (CycleTimeLightController.this.enabled && this.trafficLight.getTrafficLightColor().isGreen())
171             {
172                 try
173                 {
174                     // schedule green
175                     Time minRedTime = CycleTimeLightController.this.simulator.getSimulatorAbsTime().plus(MIN_RED_TIME);
176                     Time cycleRedTime = CycleTimeLightController.this.greenStarts.get(this.trafficLight)
177                             .plus(CycleTimeLightController.this.cTime);
178                     Time green;
179                     if (minRedTime.ge(cycleRedTime))
180                     {
181                         getSimulator().getLogger().always().info("Traffic light set to RED");
182                         this.trafficLight.setTrafficLightColor(TrafficLightColor.RED);
183                         green = minRedTime;
184                     }
185                     else
186                     {
187                         getSimulator().getLogger().always().info("Traffic light set to YELLOW (RED over 'MIN_RED_TIME')");
188                         this.trafficLight.setTrafficLightColor(TrafficLightColor.YELLOW);
189                         CycleTimeLightController.this.redEvents.put(this.trafficLight,
190                                 CycleTimeLightController.this.simulator.scheduleEventRel(MIN_RED_TIME,
191                                         CycleTimeLightController.this, "setRed", new Object[] {this.trafficLight}));
192                         green = cycleRedTime;
193                     }
194                     CycleTimeLightController.this.greenEvents.put(this.trafficLight,
195                             CycleTimeLightController.this.simulator.scheduleEventAbsTime(green, CycleTimeLightController.this,
196                                     "setGreen", new Object[] {this.trafficLight}));
197                 }
198                 catch (SimRuntimeException exception)
199                 {
200                     throw new RuntimeException(exception);
201                 }
202             }
203         }
204 
205     }
206 
207 }