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