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