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