View Javadoc
1   package org.opentrafficsim.demo.carFollowing;
2   
3   import static org.opentrafficsim.core.gtu.GTUType.CAR;
4   
5   import java.awt.Frame;
6   import java.rmi.RemoteException;
7   import java.util.ArrayList;
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.SwingUtilities;
15  
16  import org.djunits.unit.TimeUnit;
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.base.parameters.Parameters;
28  import org.opentrafficsim.core.compatibility.Compatible;
29  import org.opentrafficsim.core.dsol.OTSModelInterface;
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.network.NetworkException;
36  import org.opentrafficsim.core.network.OTSNetwork;
37  import org.opentrafficsim.core.network.OTSNode;
38  import org.opentrafficsim.graphs.FundamentalDiagram;
39  import org.opentrafficsim.road.animation.AnimationToggles;
40  import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
41  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
42  import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedGTUFollowingTacticalPlanner;
43  import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
44  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMOld;
45  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
46  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
47  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
48  import org.opentrafficsim.road.network.factory.LaneFactory;
49  import org.opentrafficsim.road.network.lane.CrossSectionLink;
50  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
51  import org.opentrafficsim.road.network.lane.Lane;
52  import org.opentrafficsim.road.network.lane.LaneType;
53  import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
54  import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
55  import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
56  import org.opentrafficsim.simulationengine.OTSSimulationException;
57  import org.opentrafficsim.simulationengine.SimpleSimulatorInterface;
58  
59  import nl.tudelft.simulation.dsol.SimRuntimeException;
60  import nl.tudelft.simulation.dsol.gui.swing.TablePanel;
61  import nl.tudelft.simulation.dsol.simtime.SimTimeDoubleUnit;
62  import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
63  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
64  
65  /**
66   * Demonstrate the FundamentalDiagram plot.
67   * <p>
68   * Copyright (c) 2013-2018 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: 2018-09-19 13:55:45 +0200 (Wed, 19 Sep 2018) $, @version $Revision: 4006 $, 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 FundamentalDiagrams extends AbstractWrappableAnimation implements UNITS
76  {
77      /** */
78      private static final long serialVersionUID = 1L;
79  
80      /** The model. */
81      private FundamentalDiagramPlotsModel model;
82  
83      /** Create a FundamentalDiagrams simulation. */
84      public FundamentalDiagrams()
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                     FundamentalDiagrams fundamentalDiagrams = new FundamentalDiagrams();
128                     fundamentalDiagrams.buildAnimator(Time.ZERO, Duration.ZERO, new Duration(3600.0, SECOND),
129                             fundamentalDiagrams.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()
142     {
143         this.model = new FundamentalDiagramPlotsModel(this.savedUserModifiedProperties);
144         return this.model;
145     }
146 
147     /** {@inheritDoc} */
148     @Override
149     protected final void addAnimationToggles()
150     {
151         AnimationToggles.setTextAnimationTogglesStandard(this);
152     }
153 
154     /** {@inheritDoc} */
155     @Override
156     protected final void addTabs(final SimpleSimulatorInterface simulator) throws OTSSimulationException
157     {
158         final int panelsPerRow = 3;
159         TablePanel charts = new TablePanel(4, panelsPerRow);
160         for (int plotNumber = 0; plotNumber < 10; plotNumber++)
161         {
162             Length detectorLocation = new Length(400 + 500 * plotNumber, METER);
163             FundamentalDiagram fd;
164             try
165             {
166                 fd = new FundamentalDiagram("Fundamental Diagram at " + detectorLocation.getSI() + "m", new Duration(1, MINUTE),
167                         this.model.getLane(), detectorLocation, Compatible.EVERYTHING, simulator);
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         addTab(getTabCount(), "statistics", 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+
203      * <a 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-2018 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
208      * <br>
209      * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
210      * <p>
211      * $LastChangedDate: 2018-09-19 13:55:45 +0200 (Wed, 19 Sep 2018) $, @version $Revision: 4006 $, by $Author: averbraeck $,
212      * initial version ug 1, 2014 <br>
213      * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
214      */
215     class FundamentalDiagramPlotsModel implements OTSModelInterface, UNITS
216     {
217         /** */
218         private static final long serialVersionUID = 20140820L;
219 
220         /** The simulator. */
221         private DEVSSimulatorInterface.TimeDoubleUnit simulator;
222 
223         /** The network. */
224         private OTSNetwork network = new OTSNetwork("network");
225 
226         /** The headway (inter-vehicle time). */
227         private Duration headway;
228 
229         /** Number of cars created. */
230         private int carsCreated = 0;
231 
232         /** Type of all GTUs. */
233         private GTUType gtuType = CAR;
234 
235         /** The car following model, e.g. IDM Plus for cars. */
236         private GTUFollowingModelOld carFollowingModelCars;
237 
238         /** The car following model, e.g. IDM Plus for trucks. */
239         private GTUFollowingModelOld carFollowingModelTrucks;
240 
241         /** The probability that the next generated GTU is a passenger car. */
242         private double carProbability;
243 
244         /** The blocking car. */
245         private LaneBasedIndividualGTU block = null;
246 
247         /** Minimum distance. */
248         private Length minimumDistance = new Length(0, METER);
249 
250         /** Maximum distance. */
251         private Length maximumDistance = new Length(5000, METER);
252 
253         /** The Lane containing the simulated Cars. */
254         private Lane lane;
255 
256         /** The speed limit. */
257         private Speed speedLimit = new Speed(100, KM_PER_HOUR);
258 
259         /** The fundamental diagram plots. */
260         private List<FundamentalDiagram> fundamentalDiagrams = new ArrayList<>();
261 
262         /** User settable properties. */
263         private List<Property<?>> fundamentalDiagramProperties = null;
264 
265         /** The random number generator used to decide what kind of GTU to generate. */
266         private Random randomGenerator = new Random(12345);
267 
268         /**
269          * @param properties ArrayList&lt;AbstractProperty&lt;?&gt;&gt;; the properties
270          */
271         FundamentalDiagramPlotsModel(final List<Property<?>> properties)
272         {
273             this.fundamentalDiagramProperties = properties;
274         }
275 
276         /** {@inheritDoc} */
277         @Override
278         public final void constructModel(final SimulatorInterface<Time, Duration, SimTimeDoubleUnit> theSimulator)
279                 throws SimRuntimeException
280         {
281             try
282             {
283                 this.simulator = (DEVSSimulatorInterface.TimeDoubleUnit) theSimulator;
284                 OTSNode from = new OTSNode(this.network, "From", new OTSPoint3D(getMinimumDistance().getSI(), 0, 0));
285                 OTSNode to = new OTSNode(this.network, "To", new OTSPoint3D(getMaximumDistance().getSI(), 0, 0));
286                 OTSNode end = new OTSNode(this.network, "End", new OTSPoint3D(getMaximumDistance().getSI() + 50.0, 0, 0));
287                 LaneType laneType = LaneType.TWO_WAY_LANE;
288                 this.lane =
289                         LaneFactory.makeLane(this.network, "Lane", from, to, null, laneType, this.speedLimit, this.simulator);
290                 CrossSectionLink endLink = LaneFactory.makeLink(this.network, "endLink", to, end, null, simulator);
291                 // No overtaking, single lane
292                 Lane sinkLane = new Lane(endLink, "sinkLane", this.lane.getLateralCenterPosition(1.0),
293                         this.lane.getLateralCenterPosition(1.0), this.lane.getWidth(1.0), this.lane.getWidth(1.0), laneType,
294                         this.speedLimit, new OvertakingConditions.None());
295                 new SinkSensor(sinkLane, new Length(10.0, METER), this.simulator);
296             }
297             catch (NamingException | NetworkException | OTSGeometryException exception)
298             {
299                 exception.printStackTrace();
300             }
301 
302             // create SinkLane
303 
304             for (Property<?> p : this.fundamentalDiagramProperties)
305             {
306                 if (p instanceof SelectionProperty)
307                 {
308                     SelectionProperty sp = (SelectionProperty) p;
309                     if ("CarFollowingModel".equals(sp.getKey()))
310                     {
311                         String modelName = sp.getValue();
312                         if (modelName.equals("IDM"))
313                         {
314                             this.carFollowingModelCars = new IDMOld(new Acceleration(1, METER_PER_SECOND_2),
315                                     new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
316                                     1d);
317                             this.carFollowingModelTrucks = new IDMOld(new Acceleration(0.5, METER_PER_SECOND_2),
318                                     new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
319                                     1d);
320                         }
321                         else if (modelName.equals("IDM+"))
322                         {
323                             this.carFollowingModelCars = new IDMPlusOld(new Acceleration(1, METER_PER_SECOND_2),
324                                     new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
325                                     1d);
326                             this.carFollowingModelTrucks = new IDMPlusOld(new Acceleration(0.5, METER_PER_SECOND_2),
327                                     new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
328                                     1d);
329                         }
330                         else
331                         {
332                             throw new Error("Car following model " + modelName + " not implemented");
333                         }
334                     }
335                     else
336                     {
337                         throw new Error("Unhandled SelectionProperty " + p.getKey());
338                     }
339                 }
340                 else if (p instanceof ProbabilityDistributionProperty)
341                 {
342                     ProbabilityDistributionProperty pdp = (ProbabilityDistributionProperty) p;
343                     String modelName = p.getKey();
344                     if (modelName.equals("TrafficComposition"))
345                     {
346                         this.carProbability = pdp.getValue()[0];
347                     }
348                     else
349                     {
350                         throw new Error("Unhandled ProbabilityDistributionProperty " + p.getKey());
351                     }
352                 }
353                 else
354                 {
355                     throw new Error("Unhandled property: " + p);
356                 }
357             }
358 
359             // 1500 [veh / hour] == 2.4s headway
360             this.headway = new Duration(3600.0 / 1500.0, SECOND);
361 
362             try
363             {
364                 // Schedule creation of the first car (this will re-schedule itself one headway later, etc.).
365                 this.simulator.scheduleEventAbs(Time.ZERO, this, this, "generateCar", null);
366                 // Create a block at t = 5 minutes
367                 this.simulator.scheduleEventAbs(new Time(300, TimeUnit.BASE_SECOND), this, this, "createBlock", null);
368                 // Remove the block at t = 7 minutes
369                 this.simulator.scheduleEventAbs(new Time(420, TimeUnit.BASE_SECOND), this, this, "removeBlock", null);
370                 // Schedule regular updates of the graph
371                 for (int t = 1; t <= 1800; t++)
372                 {
373                     this.simulator.scheduleEventAbs(new Time(t - 0.001, TimeUnit.BASE_SECOND), this, this, "drawGraphs", null);
374                 }
375             }
376             catch (SimRuntimeException exception)
377             {
378                 exception.printStackTrace();
379             }
380         }
381 
382         /**
383          * Set up the block.
384          * @throws RemoteException on communications failure
385          */
386         protected final void createBlock() throws RemoteException
387         {
388             Length initialPosition = new Length(4000, METER);
389             Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
390             try
391             {
392                 initialPositions.add(new DirectedLanePosition(this.getLane(), initialPosition, GTUDirectionality.DIR_PLUS));
393                 Parameters parameters = DefaultsFactory.getDefaultParameters();
394                 // LaneBasedBehavioralCharacteristics drivingCharacteristics =
395                 // new LaneBasedBehavioralCharacteristics(this.carFollowingModelCars, this.laneChangeModel);
396 
397                 this.block = new LaneBasedIndividualGTU("999999", this.gtuType, new Length(4, METER), new Length(1.8, METER),
398                         Speed.ZERO, Length.createSI(2.0), this.simulator, this.network);
399                 LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(
400                         new LaneBasedGTUFollowingTacticalPlanner(this.carFollowingModelCars, this.block), this.block);
401                 this.block.setParameters(parameters);
402                 this.block.initWithAnimation(strategicalPlanner, initialPositions, Speed.ZERO, DefaultCarAnimation.class,
403                         FundamentalDiagrams.this.getColorer());
404             }
405             catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
406             {
407                 exception.printStackTrace();
408             }
409         }
410 
411         /**
412          * Remove the block.
413          */
414         protected final void removeBlock()
415         {
416             this.block.destroy();
417             this.block = null;
418         }
419 
420         /**
421          * Generate cars at a fixed rate (implemented by re-scheduling this method).
422          */
423         protected final void generateCar()
424         {
425             boolean generateTruck = this.randomGenerator.nextDouble() > this.carProbability;
426             Length initialPosition = new Length(0, METER);
427             Speed initialSpeed = new Speed(100, KM_PER_HOUR);
428             Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
429             try
430             {
431                 initialPositions.add(new DirectedLanePosition(this.getLane(), initialPosition, GTUDirectionality.DIR_PLUS));
432                 Length vehicleLength = new Length(generateTruck ? 15 : 4, METER);
433                 GTUFollowingModelOld gtuFollowingModel =
434                         generateTruck ? this.carFollowingModelTrucks : this.carFollowingModelCars;
435                 if (null == gtuFollowingModel)
436                 {
437                     throw new Error("gtuFollowingModel is null");
438                 }
439                 Parameters parameters = DefaultsFactory.getDefaultParameters();
440                 // LaneBasedBehavioralCharacteristics drivingCharacteristics =
441                 // new LaneBasedBehavioralCharacteristics(gtuFollowingModel, this.laneChangeModel);
442 
443                 LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU("" + (++this.carsCreated), this.gtuType, vehicleLength,
444                         new Length(1.8, METER), new Speed(200, KM_PER_HOUR), vehicleLength.multiplyBy(0.5), this.simulator,
445                         this.network);
446                 LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(
447                         new LaneBasedGTUFollowingTacticalPlanner(gtuFollowingModel, gtu), gtu);
448                 gtu.setParameters(parameters);
449                 gtu.initWithAnimation(strategicalPlanner, initialPositions, initialSpeed, DefaultCarAnimation.class,
450                         FundamentalDiagrams.this.getColorer());
451 
452                 this.simulator.scheduleEventRel(this.headway, this, this, "generateCar", null);
453             }
454             catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
455             {
456                 exception.printStackTrace();
457             }
458         }
459 
460         /**
461         * 
462         */
463         protected final void drawGraphs()
464         {
465             // Notify the Fundamental Diagram plots that the underlying data has changed
466             for (FundamentalDiagram fd : this.fundamentalDiagrams)
467             {
468                 fd.reGraph();
469             }
470         }
471 
472         /** {@inheritDoc} */
473         @Override
474         public final SimulatorInterface<Time, Duration, SimTimeDoubleUnit> getSimulator()
475         {
476             return this.simulator;
477         }
478 
479         /** {@inheritDoc} */
480         @Override
481         public OTSNetwork getNetwork()
482         {
483             return this.network;
484         }
485 
486         /**
487          * @return fundamentalDiagramPlots
488          */
489         public final List<FundamentalDiagram> getFundamentalDiagrams()
490         {
491             return this.fundamentalDiagrams;
492         }
493 
494         /**
495          * @return minimumDistance
496          */
497         public final Length getMinimumDistance()
498         {
499             return this.minimumDistance;
500         }
501 
502         /**
503          * @return maximumDistance
504          */
505         public final Length getMaximumDistance()
506         {
507             return this.maximumDistance;
508         }
509 
510         /**
511          * @return lane.
512          */
513         public Lane getLane()
514         {
515             return this.lane;
516         }
517     }
518 
519     /** {@inheritDoc} */
520     @Override
521     public final String toString()
522     {
523         return "FundamentalDiagrams [model=" + this.model + "]";
524     }
525 }