View Javadoc
1   package org.opentrafficsim.demo;
2   
3   import java.io.Serializable;
4   import java.rmi.RemoteException;
5   import java.util.Arrays;
6   import java.util.LinkedHashMap;
7   import java.util.LinkedHashSet;
8   import java.util.Map;
9   import java.util.Set;
10  
11  import javax.naming.NamingException;
12  
13  import org.djunits.unit.DirectionUnit;
14  import org.djunits.unit.DurationUnit;
15  import org.djunits.unit.LengthUnit;
16  import org.djunits.unit.SpeedUnit;
17  import org.djunits.unit.util.UNITS;
18  import org.djunits.value.vdouble.scalar.Direction;
19  import org.djunits.value.vdouble.scalar.Duration;
20  import org.djunits.value.vdouble.scalar.Length;
21  import org.djunits.value.vdouble.scalar.Speed;
22  import org.djunits.value.vdouble.scalar.base.DoubleScalar;
23  import org.opentrafficsim.base.parameters.ParameterException;
24  import org.opentrafficsim.core.compatibility.Compatible;
25  import org.opentrafficsim.core.distributions.Distribution;
26  import org.opentrafficsim.core.distributions.Distribution.FrequencyAndObject;
27  import org.opentrafficsim.core.distributions.Generator;
28  import org.opentrafficsim.core.distributions.ProbabilityException;
29  import org.opentrafficsim.core.dsol.AbstractOTSModel;
30  import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
31  import org.opentrafficsim.core.geometry.OTSGeometryException;
32  import org.opentrafficsim.core.geometry.OTSPoint3D;
33  import org.opentrafficsim.core.gtu.GTUDirectionality;
34  import org.opentrafficsim.core.gtu.GTUException;
35  import org.opentrafficsim.core.gtu.GTUType;
36  import org.opentrafficsim.core.idgenerator.IdGenerator;
37  import org.opentrafficsim.core.network.NetworkException;
38  import org.opentrafficsim.core.network.Node;
39  import org.opentrafficsim.core.network.route.FixedRouteGenerator;
40  import org.opentrafficsim.core.network.route.Route;
41  import org.opentrafficsim.core.parameters.ParameterFactory;
42  import org.opentrafficsim.core.units.distributions.ContinuousDistDoubleScalar;
43  import org.opentrafficsim.draw.road.TrafficLightAnimation;
44  import org.opentrafficsim.road.gtu.generator.CFRoomChecker;
45  import org.opentrafficsim.road.gtu.generator.GeneratorPositions;
46  import org.opentrafficsim.road.gtu.generator.LaneBasedGTUGenerator;
47  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedTemplateGTUType;
48  import org.opentrafficsim.road.gtu.generator.characteristics.LaneBasedTemplateGTUTypeDistribution;
49  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusFactory;
50  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.DefaultLMRSPerceptionFactory;
51  import org.opentrafficsim.road.gtu.lane.tactical.lmrs.LMRSFactory;
52  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
53  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlannerFactory;
54  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlannerFactory;
55  import org.opentrafficsim.road.network.OTSRoadNetwork;
56  import org.opentrafficsim.road.network.factory.LaneFactory;
57  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
58  import org.opentrafficsim.road.network.lane.Lane;
59  import org.opentrafficsim.road.network.lane.LaneType;
60  import org.opentrafficsim.road.network.lane.OTSRoadNode;
61  import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
62  import org.opentrafficsim.road.network.lane.object.trafficlight.SimpleTrafficLight;
63  import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLight;
64  import org.opentrafficsim.road.network.lane.object.trafficlight.TrafficLightColor;
65  
66  import nl.tudelft.simulation.dsol.SimRuntimeException;
67  import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterDouble;
68  import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterException;
69  import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterMap;
70  import nl.tudelft.simulation.jstats.distributions.DistContinuous;
71  import nl.tudelft.simulation.jstats.distributions.DistErlang;
72  import nl.tudelft.simulation.jstats.distributions.DistUniform;
73  import nl.tudelft.simulation.jstats.streams.MersenneTwister;
74  import nl.tudelft.simulation.jstats.streams.StreamInterface;
75  
76  /**
77   * Simulate four double lane roads with a crossing in the middle.
78   * <p>
79   * Copyright (c) 2013-2020 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
80   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
81   * </p>
82   * $LastChangedDate: 2016-10-28 16:34:11 +0200 (Fri, 28 Oct 2016) $, @version $Revision: 2429 $, by $Author: pknoppers $,
83   * initial version ug 1, 2014 <br>
84   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
85   */
86  public class CrossingTrafficLightsModel extends AbstractOTSModel implements UNITS
87  {
88      /** */
89      private static final long serialVersionUID = 20140815L;
90  
91      /** The network. */
92      private final OTSRoadNetwork network;
93  
94      /** the random stream for this demo. */
95      private StreamInterface stream = new MersenneTwister(555);
96  
97      /** Id generator (used by all generators). */
98      private IdGenerator idGenerator = new IdGenerator("");
99  
100     /** The probability distribution for the variable part of the headway. */
101     @SuppressWarnings("checkstyle:visibilitymodifier")
102     protected DistContinuous headwayGenerator;
103 
104     /** The probability that the next generated GTU is a passenger car. */
105     private double carProbability;
106 
107     /** the strategical planner factory for cars. */
108     private LaneBasedStrategicalPlannerFactory<LaneBasedStrategicalPlanner> strategicalPlannerFactoryCar;
109 
110     /** the strategical planner factory for trucks. */
111     private LaneBasedStrategicalPlannerFactory<LaneBasedStrategicalPlanner> strategicalPlannerFactoryTruck;
112 
113     /** The speed limit on all Lanes. */
114     private Speed speedLimit = new Speed(80, KM_PER_HOUR);
115 
116     /** Fixed green time. */
117     private static final Duration TGREEN = new Duration(39.0, DurationUnit.SI);
118 
119     /** Fixed yellow time. */
120     private static final Duration TYELLOW = new Duration(6.0, DurationUnit.SI);
121 
122     /** Fixed red time. */
123     private static final Duration TRED = new Duration(45.0, DurationUnit.SI);
124 
125     /**
126      * @param simulator OTSSimulatorInterface; the simulator for this model
127      */
128     public CrossingTrafficLightsModel(final OTSSimulatorInterface simulator)
129     {
130         super(simulator);
131         this.network  = new OTSRoadNetwork("network", true, simulator);
132         createInputParameters();
133     }
134 
135     /**
136      * Create input parameters for the networks demo.
137      */
138     private void createInputParameters()
139     {
140         try
141         {
142             InputParameterHelper.makeInputParameterMapCarTruck(this.inputParameterMap, 1.0);
143             InputParameterMap genericMap = (InputParameterMap) this.inputParameterMap.get("generic");
144             genericMap.add(new InputParameterDouble("flow", "Flow per input lane", "Traffic flow per input lane", 250d, 0d,
145                     400d, true, true, "%.0f veh/h", 1.5));
146         }
147         catch (InputParameterException e)
148         {
149             e.printStackTrace();
150         }
151     }
152 
153     /** {@inheritDoc} */
154     @Override
155     public final void constructModel() throws SimRuntimeException
156     {
157         try
158         {
159             OTSRoadNode[][] nodes = new OTSRoadNode[4][4];
160             nodes[0][0] = new OTSRoadNode(this.network, "sn1", new OTSPoint3D(10, -500),
161                     new Direction(90, DirectionUnit.EAST_DEGREE));
162             nodes[0][1] =
163                     new OTSRoadNode(this.network, "sn2", new OTSPoint3D(10, -20), new Direction(90, DirectionUnit.EAST_DEGREE));
164             nodes[0][2] =
165                     new OTSRoadNode(this.network, "sn3", new OTSPoint3D(10, +20), new Direction(90, DirectionUnit.EAST_DEGREE));
166             nodes[0][3] = new OTSRoadNode(this.network, "sn4", new OTSPoint3D(10, +600),
167                     new Direction(90, DirectionUnit.EAST_DEGREE));
168 
169             nodes[1][0] = new OTSRoadNode(this.network, "we1", new OTSPoint3D(-500, -10), Direction.ZERO);
170             nodes[1][1] = new OTSRoadNode(this.network, "we2", new OTSPoint3D(-20, -10), Direction.ZERO);
171             nodes[1][2] = new OTSRoadNode(this.network, "we3", new OTSPoint3D(+20, -10), Direction.ZERO);
172             nodes[1][3] = new OTSRoadNode(this.network, "we4", new OTSPoint3D(+600, -10), Direction.ZERO);
173 
174             nodes[2][0] = new OTSRoadNode(this.network, "ns1", new OTSPoint3D(-10, +500),
175                     new Direction(270, DirectionUnit.EAST_DEGREE));
176             nodes[2][1] = new OTSRoadNode(this.network, "ns2", new OTSPoint3D(-10, +20),
177                     new Direction(270, DirectionUnit.EAST_DEGREE));
178             nodes[2][2] = new OTSRoadNode(this.network, "ns3", new OTSPoint3D(-10, -20),
179                     new Direction(270, DirectionUnit.EAST_DEGREE));
180             nodes[2][3] = new OTSRoadNode(this.network, "ns4", new OTSPoint3D(-10, -600),
181                     new Direction(270, DirectionUnit.EAST_DEGREE));
182 
183             nodes[3][0] = new OTSRoadNode(this.network, "ew1", new OTSPoint3D(+500, 10),
184                     new Direction(180, DirectionUnit.EAST_DEGREE));
185             nodes[3][1] = new OTSRoadNode(this.network, "ew2", new OTSPoint3D(+20, 10),
186                     new Direction(180, DirectionUnit.EAST_DEGREE));
187             nodes[3][2] = new OTSRoadNode(this.network, "ew3", new OTSPoint3D(-20, 10),
188                     new Direction(180, DirectionUnit.EAST_DEGREE));
189             nodes[3][3] = new OTSRoadNode(this.network, "ew4", new OTSPoint3D(-600, 10),
190                     new Direction(180, DirectionUnit.EAST_DEGREE));
191 
192             LaneType laneType = this.network.getLaneType(LaneType.DEFAULTS.TWO_WAY_LANE);
193 
194             Map<Lane, SimpleTrafficLight> trafficLights = new LinkedHashMap<>();
195 
196             this.carProbability = (double) getInputParameter("generic.carProbability");
197             ParameterFactory params = new InputParameterHelper(getInputParameterMap());
198             this.strategicalPlannerFactoryCar = new LaneBasedStrategicalRoutePlannerFactory(
199                     new LMRSFactory(new IDMPlusFactory(this.stream), new DefaultLMRSPerceptionFactory()), params);
200             this.strategicalPlannerFactoryTruck = new LaneBasedStrategicalRoutePlannerFactory(
201                     new LMRSFactory(new IDMPlusFactory(this.stream), new DefaultLMRSPerceptionFactory()), params);
202             this.idGenerator = new IdGenerator("");
203             double contP = (double) getInputParameter("generic.flow");
204             Duration averageHeadway = new Duration(3600.0 / contP, SECOND);
205             Duration minimumHeadway = new Duration(3, SECOND);
206             this.headwayGenerator =
207                     new DistErlang(new MersenneTwister(1234), 4, DoubleScalar.minus(averageHeadway, minimumHeadway).getSI());
208 
209             for (int i = 0; i < 4; i++)
210             {
211                 for (int j = 0; j < 3; j++)
212                 {
213                     Lane[] lanes = LaneFactory.makeMultiLane(this.network,
214                             "Lane_" + nodes[i][j].getId() + "-" + nodes[i][j + 1].getId(), nodes[i][j], nodes[i][j + 1], null,
215                             2, laneType, this.speedLimit, this.simulator);
216                     if (j == 0)
217                     {
218                         for (Lane lane : lanes)
219                         {
220                             // make a generator for the lane
221                             Generator<Route> routeGenerator = new FixedRouteGenerator(new Route("main",
222                                     Arrays.asList(new Node[] {nodes[i][0], nodes[i][1], nodes[i][2], nodes[i][3]})));
223                             makeGenerator(lane, routeGenerator);
224 
225                             // add the traffic light
226                             SimpleTrafficLight tl = new SimpleTrafficLight(lane.getId() + "_TL", lane,
227                                     new Length(lane.getLength().minus(new Length(10.0, LengthUnit.METER))), this.simulator);
228                             trafficLights.put(lane, tl);
229 
230                             try
231                             {
232                                 new TrafficLightAnimation(tl, this.simulator);
233                             }
234                             catch (RemoteException | NamingException exception)
235                             {
236                                 throw new NetworkException(exception);
237                             }
238 
239                             if (i == 0 || i == 2)
240                             {
241                                 this.simulator.scheduleEventRel(Duration.ZERO, this, this, "changeTL", new Object[] {tl});
242                             }
243                             else
244                             {
245                                 this.simulator.scheduleEventRel(TRED, this, this, "changeTL", new Object[] {tl});
246                             }
247                         }
248                     }
249                     if (j == 2)
250                     {
251                         for (Lane lane : lanes)
252                         {
253                             new SinkSensor(lane, new Length(500.0, METER), Compatible.EVERYTHING, this.simulator);
254                         }
255                     }
256                 }
257             }
258         }
259         catch (SimRuntimeException | NamingException | NetworkException | OTSGeometryException | GTUException
260                 | InputParameterException | ProbabilityException | ParameterException exception)
261         {
262             exception.printStackTrace();
263         }
264     }
265 
266     /**
267      * Build a generator.
268      * @param lane Lane; the lane on which the generated GTUs are placed
269      * @param routeGenerator the fixed route for this lane
270      * @return LaneBasedGTUGenerator
271      * @throws GTUException when lane position out of bounds
272      * @throws SimRuntimeException when generation scheduling fails
273      * @throws ProbabilityException when probability distribution is wrong
274      * @throws ParameterException when a parameter is missing for the perception of the GTU
275      * @throws InputParameterException when a parameter is missing for the perception of the GTU
276      */
277     private LaneBasedGTUGenerator makeGenerator(final Lane lane, final Generator<Route> routeGenerator)
278             throws GTUException, SimRuntimeException, ProbabilityException, ParameterException, InputParameterException
279     {
280         Distribution<LaneBasedTemplateGTUType> distribution = new Distribution<>(this.stream);
281         Length initialPosition = new Length(16, METER);
282         Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
283         initialPositions.add(new DirectedLanePosition(lane, initialPosition, GTUDirectionality.DIR_PLUS));
284 
285         LaneBasedTemplateGTUType template = makeTemplate(this.stream, lane,
286                 new ContinuousDistDoubleScalar.Rel<Length, LengthUnit>(new DistUniform(this.stream, 3, 6), METER),
287                 new ContinuousDistDoubleScalar.Rel<Length, LengthUnit>(new DistUniform(this.stream, 1.6, 2.0), METER),
288                 new ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit>(new DistUniform(this.stream, 140, 180), KM_PER_HOUR),
289                 initialPositions, this.strategicalPlannerFactoryCar, routeGenerator);
290         // System.out.println("Constructed template " + template);
291         distribution.add(new FrequencyAndObject<>(this.carProbability, template));
292         template = makeTemplate(this.stream, lane,
293                 new ContinuousDistDoubleScalar.Rel<Length, LengthUnit>(new DistUniform(this.stream, 8, 14), METER),
294                 new ContinuousDistDoubleScalar.Rel<Length, LengthUnit>(new DistUniform(this.stream, 2.0, 2.5), METER),
295                 new ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit>(new DistUniform(this.stream, 100, 140), KM_PER_HOUR),
296                 initialPositions, this.strategicalPlannerFactoryTruck, routeGenerator);
297         // System.out.println("Constructed template " + template);
298         distribution.add(new FrequencyAndObject<>(1.0 - this.carProbability, template));
299         LaneBasedTemplateGTUTypeDistribution templateDistribution = new LaneBasedTemplateGTUTypeDistribution(distribution);
300         LaneBasedGTUGenerator.RoomChecker roomChecker = new CFRoomChecker();
301         return new LaneBasedGTUGenerator(lane.getId(), new Generator<Duration>()
302         {
303             @Override
304             public Duration draw()
305             {
306                 return new Duration(CrossingTrafficLightsModel.this.headwayGenerator.draw(), DurationUnit.SI);
307             }
308         }, templateDistribution, GeneratorPositions.create(initialPositions, this.stream), this.network, this.simulator,
309                 roomChecker, this.idGenerator);
310     }
311 
312     /**
313      * @param randStream StreamInterface; the random stream to use
314      * @param lane Lane; reference lane to generate GTUs on
315      * @param lengthDistribution ContinuousDistDoubleScalar.Rel&lt;Length,LengthUnit&gt;; distribution of the GTU length
316      * @param widthDistribution ContinuousDistDoubleScalar.Rel&lt;Length,LengthUnit&gt;; distribution of the GTU width
317      * @param maximumSpeedDistribution ContinuousDistDoubleScalar.Rel&lt;Speed,SpeedUnit&gt;; distribution of the GTU's maximum
318      *            speed
319      * @param initialPositions Set&lt;DirectedLanePosition&gt;; initial position(s) of the GTU on the Lane(s)
320      * @param strategicalPlannerFactory LaneBasedStrategicalPlannerFactory&lt;LaneBasedStrategicalPlanner&gt;; factory to
321      *            generate the strategical planner for the GTU
322      * @param routeGenerator the route generator
323      * @return template for a GTU
324      * @throws GTUException when characteristics cannot be initialized
325      */
326     @SuppressWarnings("checkstyle:parameternumber")
327     LaneBasedTemplateGTUType makeTemplate(final StreamInterface randStream, final Lane lane,
328             final ContinuousDistDoubleScalar.Rel<Length, LengthUnit> lengthDistribution,
329             final ContinuousDistDoubleScalar.Rel<Length, LengthUnit> widthDistribution,
330             final ContinuousDistDoubleScalar.Rel<Speed, SpeedUnit> maximumSpeedDistribution,
331             final Set<DirectedLanePosition> initialPositions,
332             final LaneBasedStrategicalPlannerFactory<LaneBasedStrategicalPlanner> strategicalPlannerFactory,
333             final Generator<Route> routeGenerator) throws GTUException
334     {
335         return new LaneBasedTemplateGTUType(this.network.getGtuType(GTUType.DEFAULTS.CAR), new Generator<Length>()
336         {
337             @Override
338             public Length draw()
339             {
340                 return lengthDistribution.draw();
341             }
342         }, new Generator<Length>()
343         {
344             @Override
345             public Length draw()
346             {
347                 return widthDistribution.draw();
348             }
349         }, new Generator<Speed>()
350         {
351             @Override
352             public Speed draw()
353             {
354                 return maximumSpeedDistribution.draw();
355             }
356         }, strategicalPlannerFactory, routeGenerator);
357 
358     }
359 
360     /**
361      * Change the traffic light to a new color.
362      * @param tl TrafficLight; the traffic light
363      * @throws SimRuntimeException when scheduling fails
364      */
365     protected final void changeTL(final TrafficLight tl) throws SimRuntimeException
366     {
367         if (tl.getTrafficLightColor().isRed())
368         {
369             tl.setTrafficLightColor(TrafficLightColor.GREEN);
370             this.simulator.scheduleEventRel(TGREEN, this, this, "changeTL", new Object[] {tl});
371         }
372         else if (tl.getTrafficLightColor().isGreen())
373         {
374             tl.setTrafficLightColor(TrafficLightColor.YELLOW);
375             this.simulator.scheduleEventRel(TYELLOW, this, this, "changeTL", new Object[] {tl});
376         }
377         else if (tl.getTrafficLightColor().isYellow())
378         {
379             tl.setTrafficLightColor(TrafficLightColor.RED);
380             this.simulator.scheduleEventRel(TRED, this, this, "changeTL", new Object[] {tl});
381         }
382     }
383 
384     /** {@inheritDoc} */
385     @Override
386     public OTSRoadNetwork getNetwork()
387     {
388         return this.network;
389     }
390 
391     /** {@inheritDoc} */
392     @Override
393     public Serializable getSourceId()
394     {
395         return "CrossingTrafficLightsModel";
396     }
397 }