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