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