View Javadoc
1   package org.opentrafficsim.demo.carFollowing;
2   
3   import java.awt.Frame;
4   import java.awt.geom.Rectangle2D;
5   import java.rmi.RemoteException;
6   import java.util.ArrayList;
7   import java.util.HashSet;
8   import java.util.LinkedHashSet;
9   import java.util.List;
10  import java.util.Random;
11  import java.util.Set;
12  
13  import javax.naming.NamingException;
14  import javax.swing.JPanel;
15  import javax.swing.SwingUtilities;
16  
17  import nl.tudelft.simulation.dsol.SimRuntimeException;
18  import nl.tudelft.simulation.dsol.gui.swing.TablePanel;
19  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
20  
21  import org.djunits.unit.UNITS;
22  import org.djunits.value.vdouble.scalar.Acceleration;
23  import org.djunits.value.vdouble.scalar.Duration;
24  import org.djunits.value.vdouble.scalar.Length;
25  import org.djunits.value.vdouble.scalar.Speed;
26  import org.djunits.value.vdouble.scalar.Time;
27  import org.opentrafficsim.base.modelproperties.ProbabilityDistributionProperty;
28  import org.opentrafficsim.base.modelproperties.Property;
29  import org.opentrafficsim.base.modelproperties.PropertyException;
30  import org.opentrafficsim.base.modelproperties.SelectionProperty;
31  import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
32  import org.opentrafficsim.core.dsol.OTSModelInterface;
33  import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
34  import org.opentrafficsim.core.geometry.OTSGeometryException;
35  import org.opentrafficsim.core.geometry.OTSPoint3D;
36  import org.opentrafficsim.core.gtu.GTUDirectionality;
37  import org.opentrafficsim.core.gtu.GTUException;
38  import org.opentrafficsim.core.gtu.GTUType;
39  import org.opentrafficsim.core.gtu.animation.GTUColorer;
40  import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
41  import org.opentrafficsim.core.network.LongitudinalDirectionality;
42  import org.opentrafficsim.core.network.NetworkException;
43  import org.opentrafficsim.core.network.OTSNetwork;
44  import org.opentrafficsim.core.network.OTSNode;
45  import org.opentrafficsim.graphs.FundamentalDiagramLane;
46  import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
47  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
48  import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedGTUFollowingTacticalPlanner;
49  import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
50  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMOld;
51  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
52  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
53  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
54  import org.opentrafficsim.road.network.factory.LaneFactory;
55  import org.opentrafficsim.road.network.lane.CrossSectionLink;
56  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
57  import org.opentrafficsim.road.network.lane.Lane;
58  import org.opentrafficsim.road.network.lane.LaneType;
59  import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
60  import org.opentrafficsim.road.network.lane.object.sensor.Sensor;
61  import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
62  import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
63  import org.opentrafficsim.simulationengine.OTSSimulationException;
64  import org.opentrafficsim.simulationengine.SimpleSimulatorInterface;
65  
66  /**
67   * Demonstrate the FundamentalDiagram plot.
68   * <p>
69   * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
70   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
71   * <p>
72   * $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, @version $Revision: 1401 $, by $Author: averbraeck $,
73   * initial version 17 dec. 2014 <br>
74   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
75   */
76  public class FundamentalDiagramsLane extends AbstractWrappableAnimation implements UNITS
77  {
78      /** */
79      private static final long serialVersionUID = 1L;
80  
81      /** The model. */
82      private FundamentalDiagramLanePlotsModel model;
83  
84      /** Create a FundamentalDiagrams simulation. */
85      public FundamentalDiagramsLane()
86      {
87          try
88          {
89              this.properties.add(new SelectionProperty("CarFollowingModel", "Car following model",
90                      "<html>The car following model determines "
91                              + "the acceleration that a vehicle will make taking into account nearby vehicles, "
92                              + "infrastructural restrictions (e.g. speed limit, curvature of the road) "
93                              + "capabilities of the vehicle and personality of the driver.</html>",
94                      new String[] { "IDM", "IDM+" }, 1, false, 500));
95              this.properties.add(new ProbabilityDistributionProperty("TrafficComposition", "Traffic composition",
96                      "<html>Mix of passenger cars and trucks</html>", new String[] { "passenger car", "truck" },
97                      new Double[] { 0.8, 0.2 }, false, 10));
98          }
99          catch (PropertyException exception)
100         {
101             exception.printStackTrace();
102         }
103     }
104 
105     /** {@inheritDoc} */
106     @Override
107     public final void stopTimersThreads()
108     {
109         super.stopTimersThreads();
110         this.model = null;
111     }
112 
113     /**
114      * Main program.
115      * @param args String[]; the command line arguments (not used)
116      * @throws SimRuntimeException on ???
117      */
118     public static void main(final String[] args) throws SimRuntimeException
119     {
120         // Create the simulation and wrap its panel in a JFrame. It does not get much easier/shorter than this...
121         SwingUtilities.invokeLater(new Runnable()
122         {
123             @Override
124             public void run()
125             {
126                 try
127                 {
128                     FundamentalDiagramsLane fundamentalDiagramsLane = new FundamentalDiagramsLane();
129                     fundamentalDiagramsLane.buildAnimator(new Time(0.0, SECOND), new Duration(0.0, SECOND),
130                             new Duration(3600.0, SECOND), fundamentalDiagramsLane.getProperties(), null, true);
131                 }
132                 catch (SimRuntimeException | NamingException | OTSSimulationException | PropertyException exception)
133                 {
134                     exception.printStackTrace();
135                 }
136             }
137         });
138     }
139 
140     /** {@inheritDoc} */
141     @Override
142     protected final OTSModelInterface makeModel(final GTUColorer colorer)
143     {
144         this.model = new FundamentalDiagramLanePlotsModel(this.savedUserModifiedProperties, colorer);
145         return this.model;
146     }
147 
148     /** {@inheritDoc} */
149     @Override
150     protected final Rectangle2D.Double makeAnimationRectangle()
151     {
152         return new Rectangle2D.Double(0, -100, 5000, 200);
153     }
154 
155     /** {@inheritDoc} */
156     @Override
157     protected final JPanel makeCharts(final SimpleSimulatorInterface simulator) throws OTSSimulationException
158     {
159         final int panelsPerRow = 3;
160         TablePanel charts = new TablePanel(3, panelsPerRow);
161         for (int plotNumber = 0; plotNumber < 9; plotNumber++)
162         {
163             FundamentalDiagramLane fd;
164             try
165             {
166                 Lane lane = this.model.getLane(plotNumber);
167                 int xs = (int) lane.getParentLink().getStartNode().getPoint().x;
168                 int xe = (int) lane.getParentLink().getEndNode().getPoint().x;
169                 fd = new FundamentalDiagramLane("Fundamental Diagram for [" + xs + ", " + xe + "] m", new Duration(1.0, SECOND),
170                         lane, (OTSDEVSSimulatorInterface) this.model.getSimulator());
171                 fd.setTitle("Fundamental Diagram Graph");
172                 fd.setExtendedState(Frame.MAXIMIZED_BOTH);
173                 this.model.getFundamentalDiagrams().add(fd);
174                 charts.setCell(fd.getContentPane(), plotNumber / panelsPerRow, plotNumber % panelsPerRow);
175             }
176             catch (NetworkException | RemoteException | SimRuntimeException exception)
177             {
178                 exception.printStackTrace();
179             }
180         }
181         return charts;
182     }
183 
184     /** {@inheritDoc} */
185     @Override
186     public final String shortName()
187     {
188         return "Fundamental Diagrams";
189     }
190 
191     /** {@inheritDoc} */
192     @Override
193     public final String description()
194     {
195         return "<html><h1>Fundamental Diagram Plots</H1>"
196                 + "Simulation of a single lane road of 5 km length. Vechicles are generated at a constant rate of "
197                 + "1500 veh/hour. At time 300s a blockade is inserted at position 4km; this blockade is removed at time "
198                 + "500s. This blockade simulates a bridge opening.<br>"
199                 + "The blockade causes a traffic jam that slowly dissolves after the blockade is removed.<br>"
200                 + "Output is a set of Diagrams that plot observed density, flow and speed plots against each other.</html>";
201     }
202 
203     /**
204      * Simulate a single lane road of 5 km length. Vehicles are generated at a constant rate of 1500 veh/hour. At time 300s a
205      * blockade is inserted at position 4 km; this blockade is removed at time 500s. The used car following algorithm is IDM+
206      * <a href="http://opentrafficsim.org/downloads/MOTUS%20reference.pdf"><i>Integrated Lane Change Model with Relaxation and
207      * Synchronization</i>, by Wouter J. Schakel, Victor L. Knoop and Bart van Arem, 2012</a>. <br>
208      * Output is a set of FundamentalDiagram plots for various point along the lane.
209      * <p>
210      * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
211      * <br>
212      * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
213      * <p>
214      * $LastChangedDate: 2015-09-14 01:33:02 +0200 (Mon, 14 Sep 2015) $, @version $Revision: 1401 $, by $Author: averbraeck $,
215      * initial version ug 1, 2014 <br>
216      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
217      */
218     class FundamentalDiagramLanePlotsModel implements OTSModelInterface, UNITS
219     {
220         /** */
221         private static final long serialVersionUID = 20140820L;
222 
223         /** The network. */
224         private OTSNetwork network = new OTSNetwork("network");
225 
226         /** The simulator. */
227         private OTSDEVSSimulatorInterface simulator;
228 
229         /** The headway (inter-vehicle time). */
230         private Duration headway;
231 
232         /** Number of cars created. */
233         private int carsCreated = 0;
234 
235         /** Type of all GTUs. */
236         private GTUType gtuType = new GTUType("Car");
237 
238         /** The car following model, e.g. IDM Plus for cars. */
239         private GTUFollowingModelOld carFollowingModelCars;
240 
241         /** The car following model, e.g. IDM Plus for trucks. */
242         private GTUFollowingModelOld carFollowingModelTrucks;
243 
244         /** The probability that the next generated GTU is a passenger car. */
245         private double carProbability;
246 
247         /** The blocking car. */
248         private LaneBasedIndividualGTU block = null;
249 
250         /** Starting x-position. */
251         private Length startX = new Length(0, METER);
252 
253         /** Length per lane. */
254         private Length laneLength = new Length(500, METER);
255 
256         /** The Lanes containing the simulated Cars. */
257         private List<Lane> lanes = new ArrayList<>();
258 
259         /** The speed limit. */
260         private Speed speedLimit = new Speed(100, KM_PER_HOUR);
261 
262         /** The fundamental diagram plots. */
263         private List<FundamentalDiagramLane> fundamentalDiagramsLane = new ArrayList<>();
264 
265         /** User settable properties. */
266         private List<Property<?>> fundamentalDiagramsLaneProperties = null;
267 
268         /** The random number generator used to decide what kind of GTU to generate. */
269         private Random randomGenerator = new Random(12345);
270 
271         /** The GTUColorer for the generated vehicles. */
272         private final GTUColorer gtuColorer;
273 
274         /**
275          * @param properties ArrayList&lt;AbstractProperty&lt;?&gt;&gt;; the properties
276          * @param gtuColorer the default and initial GTUColorer, e.g. a DefaultSwitchableTUColorer.
277          */
278         FundamentalDiagramLanePlotsModel(final List<Property<?>> properties, final GTUColorer gtuColorer)
279         {
280             this.fundamentalDiagramsLaneProperties = properties;
281             this.gtuColorer = gtuColorer;
282         }
283 
284         /** {@inheritDoc} */
285         @Override
286         public final void constructModel(final SimulatorInterface<Time, Duration, OTSSimTimeDouble> theSimulator)
287                 throws SimRuntimeException, RemoteException
288         {
289             this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
290             try
291             {
292                 Set<GTUType> compatibility = new HashSet<>();
293                 compatibility.add(this.gtuType);
294                 LaneType laneType = new LaneType("CarLane", compatibility);
295                 OTSNode node = new OTSNode(this.network, "Node 0", new OTSPoint3D(this.startX.getSI(), 0, 0));
296                 for (int laneNr = 0; laneNr < 10; laneNr++)
297                 {
298                     OTSNode next = new OTSNode(this.network, "Node " + (laneNr + 1),
299                             new OTSPoint3D(node.getPoint().x + this.laneLength.si, 0, 0));
300                     Lane lane = LaneFactory.makeLane(this.network, "Lane", node, next, null, laneType, this.speedLimit,
301                             this.simulator, LongitudinalDirectionality.DIR_PLUS);
302                     this.lanes.add(lane);
303                     node = next;
304                 }
305                 // create SinkLane
306                 OTSNode end = new OTSNode(this.network, "End", new OTSPoint3D(node.getPoint().x + 50.0, 0, 0));
307                 CrossSectionLink endLink =
308                         LaneFactory.makeLink(this.network, "endLink", node, end, null, LongitudinalDirectionality.DIR_PLUS);
309                 int last = this.lanes.size() - 1;
310                 Lane sinkLane = new Lane(endLink, "sinkLane", this.lanes.get(last).getLateralCenterPosition(1.0),
311                         this.lanes.get(last).getLateralCenterPosition(1.0), this.lanes.get(last).getWidth(1.0),
312                         this.lanes.get(last).getWidth(1.0), laneType, LongitudinalDirectionality.DIR_PLUS, this.speedLimit,
313                         new OvertakingConditions.None());
314                 Sensor sensor = new SinkSensor(sinkLane, new Length(10.0, METER), this.simulator);
315                 sinkLane.addSensor(sensor, GTUType.ALL);
316             }
317             catch (NamingException | NetworkException | OTSGeometryException exception)
318             {
319                 exception.printStackTrace();
320             }
321 
322             for (Property<?> p : this.fundamentalDiagramsLaneProperties)
323             {
324                 if (p instanceof SelectionProperty)
325                 {
326                     SelectionProperty sp = (SelectionProperty) p;
327                     if ("CarGollowingModel".equals(sp.getKey()))
328                     {
329                         String modelName = sp.getValue();
330                         if (modelName.equals("IDM"))
331                         {
332                             this.carFollowingModelCars = new IDMOld(new Acceleration(1, METER_PER_SECOND_2),
333                                     new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
334                                     1d);
335                             this.carFollowingModelTrucks = new IDMOld(new Acceleration(0.5, METER_PER_SECOND_2),
336                                     new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
337                                     1d);
338                         }
339                         else if (modelName.equals("IDM+"))
340                         {
341                             this.carFollowingModelCars = new IDMPlusOld(new Acceleration(1, METER_PER_SECOND_2),
342                                     new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
343                                     1d);
344                             this.carFollowingModelTrucks = new IDMPlusOld(new Acceleration(0.5, METER_PER_SECOND_2),
345                                     new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
346                                     1d);
347                         }
348                         else
349                         {
350                             throw new Error("Car following model " + modelName + " not implemented");
351                         }
352                     }
353                     else
354                     {
355                         throw new Error("Unhandled SelectionProperty " + p.getKey());
356                     }
357                 }
358                 else if (p instanceof ProbabilityDistributionProperty)
359                 {
360                     ProbabilityDistributionProperty pdp = (ProbabilityDistributionProperty) p;
361                     String modelName = p.getKey();
362                     if (modelName.equals("TrafficComposition"))
363                     {
364                         this.carProbability = pdp.getValue()[0];
365                     }
366                     else
367                     {
368                         throw new Error("Unhandled ProbabilityDistributionProperty " + p.getKey());
369                     }
370                 }
371                 else
372                 {
373                     throw new Error("Unhandled property: " + p);
374                 }
375             }
376 
377             // 1500 [veh / hour] == 2.4s headway
378             this.headway = new Duration(3600.0 / 1500.0, SECOND);
379 
380             try
381             {
382                 // Schedule creation of the first car (this will re-schedule itself one headway later, etc.).
383                 this.simulator.scheduleEventAbs(new Time(0.0, SECOND), this, this, "generateCar", null);
384                 // Create a block at t = 5 minutes
385                 this.simulator.scheduleEventAbs(new Time(1000, SECOND), this, this, "createBlock", null);
386                 // Remove the block at t = 7 minutes
387                 this.simulator.scheduleEventAbs(new Time(1200, SECOND), this, this, "removeBlock", null);
388                 // Schedule regular updates of the graph
389                 for (int t = 1; t <= this.simulator.getReplication().getTreatment().getRunLength().si / 25; t++)
390                 {
391                     this.simulator.scheduleEventAbs(new Time(25 * t - 0.001, SECOND), this, this, "drawGraphs", null);
392                 }
393             }
394             catch (SimRuntimeException exception)
395             {
396                 exception.printStackTrace();
397             }
398         }
399 
400         /**
401          * Set up the block in the last lane of the list.
402          * @throws RemoteException on communications failure
403          */
404         protected final void createBlock() throws RemoteException
405         {
406             Length initialPosition = new Length(200, METER);
407             Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
408             try
409             {
410                 initialPositions.add(new DirectedLanePosition(this.lanes.get(this.lanes.size() - 1), initialPosition,
411                         GTUDirectionality.DIR_PLUS));
412                 BehavioralCharacteristics behavioralCharacteristics = DefaultsFactory.getDefaultBehavioralCharacteristics();
413                 this.block = new LaneBasedIndividualGTU("999999", this.gtuType, new Length(4, METER), new Length(1.8, METER),
414                         new Speed(0.0, KM_PER_HOUR), this.simulator, this.network);
415                 LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics,
416                         new LaneBasedGTUFollowingTacticalPlanner(this.carFollowingModelCars, this.block), this.block);
417                 this.block.initWithAnimation(strategicalPlanner, initialPositions, new Speed(0.0, KM_PER_HOUR),
418                         DefaultCarAnimation.class, this.gtuColorer);
419             }
420             catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
421             {
422                 exception.printStackTrace();
423             }
424         }
425 
426         /**
427          * Remove the block.
428          */
429         protected final void removeBlock()
430         {
431             this.block.destroy();
432             this.block = null;
433         }
434 
435         /**
436          * Generate cars at a fixed rate (implemented by re-scheduling this method).
437          */
438         protected final void generateCar()
439         {
440             boolean generateTruck = this.randomGenerator.nextDouble() > this.carProbability;
441             Length initialPosition = new Length(0, METER);
442             Speed initialSpeed = new Speed(100, KM_PER_HOUR);
443             Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
444             try
445             {
446                 initialPositions.add(new DirectedLanePosition(this.lanes.get(0), initialPosition, GTUDirectionality.DIR_PLUS));
447                 Length vehicleLength = new Length(generateTruck ? 15 : 4, METER);
448                 GTUFollowingModelOld gtuFollowingModel =
449                         generateTruck ? this.carFollowingModelTrucks : this.carFollowingModelCars;
450                 if (null == gtuFollowingModel)
451                 {
452                     throw new Error("gtuFollowingModel is null");
453                 }
454                 BehavioralCharacteristics behavioralCharacteristics = DefaultsFactory.getDefaultBehavioralCharacteristics();
455 
456                 LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU("" + (++this.carsCreated), this.gtuType, vehicleLength,
457                         new Length(1.8, METER), new Speed(200, KM_PER_HOUR), this.simulator, this.network);
458                 LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics,
459                         new LaneBasedGTUFollowingTacticalPlanner(gtuFollowingModel, gtu), gtu);
460                 gtu.initWithAnimation(strategicalPlanner, initialPositions, initialSpeed, DefaultCarAnimation.class,
461                         this.gtuColorer);
462                 this.simulator.scheduleEventRel(this.headway, this, this, "generateCar", null);
463             }
464             catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
465             {
466                 exception.printStackTrace();
467             }
468         }
469 
470         /**
471         * 
472         */
473         protected final void drawGraphs()
474         {
475             // Notify the Fundamental Diagram plots that the underlying data has changed
476             for (FundamentalDiagramLane fd : this.fundamentalDiagramsLane)
477             {
478                 fd.reGraph();
479             }
480         }
481 
482         /** {@inheritDoc} */
483         @Override
484         public final SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator() throws RemoteException
485         {
486             return this.simulator;
487         }
488 
489         /**
490          * @return fundamentalDiagramPlots
491          */
492         public final List<FundamentalDiagramLane> getFundamentalDiagrams()
493         {
494             return this.fundamentalDiagramsLane;
495         }
496 
497         /**
498          * @param laneNr the lane in the list.
499          * @return lane.
500          */
501         public Lane getLane(final int laneNr)
502         {
503             return this.lanes.get(laneNr);
504         }
505     }
506 }