View Javadoc
1   package org.opentrafficsim.demo.carFollowing;
2   
3   import static org.opentrafficsim.road.gtu.lane.RoadGTUTypes.CAR;
4   
5   import java.awt.Frame;
6   import java.rmi.RemoteException;
7   import java.util.ArrayList;
8   import java.util.HashSet;
9   import java.util.LinkedHashSet;
10  import java.util.List;
11  import java.util.Random;
12  import java.util.Set;
13  
14  import javax.naming.NamingException;
15  import javax.swing.SwingUtilities;
16  
17  import org.djunits.unit.TimeUnit;
18  import org.djunits.unit.UNITS;
19  import org.djunits.value.vdouble.scalar.Acceleration;
20  import org.djunits.value.vdouble.scalar.Duration;
21  import org.djunits.value.vdouble.scalar.Length;
22  import org.djunits.value.vdouble.scalar.Speed;
23  import org.djunits.value.vdouble.scalar.Time;
24  import org.opentrafficsim.base.modelproperties.ProbabilityDistributionProperty;
25  import org.opentrafficsim.base.modelproperties.Property;
26  import org.opentrafficsim.base.modelproperties.PropertyException;
27  import org.opentrafficsim.base.modelproperties.SelectionProperty;
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.animation.AnimationToggles;
44  import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
45  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
46  import org.opentrafficsim.road.gtu.lane.tactical.LaneBasedGTUFollowingTacticalPlanner;
47  import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
48  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMOld;
49  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
50  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
51  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
52  import org.opentrafficsim.road.network.factory.LaneFactory;
53  import org.opentrafficsim.road.network.lane.CrossSectionLink;
54  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
55  import org.opentrafficsim.road.network.lane.Lane;
56  import org.opentrafficsim.road.network.lane.LaneType;
57  import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
58  import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
59  import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
60  import org.opentrafficsim.simulationengine.OTSSimulationException;
61  import org.opentrafficsim.simulationengine.SimpleSimulatorInterface;
62  
63  import nl.tudelft.simulation.dsol.SimRuntimeException;
64  import nl.tudelft.simulation.dsol.gui.swing.TablePanel;
65  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
66  
67  /**
68   * Demonstrate the FundamentalDiagram plot.
69   * <p>
70   * Copyright (c) 2013-2017 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: 2017-04-29 15:37:05 +0200 (Sat, 29 Apr 2017) $, @version $Revision: 3579 $, by $Author: averbraeck $,
74   * initial version 17 dec. 2014 <br>
75   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
76   */
77  public class FundamentalDiagrams extends AbstractWrappableAnimation implements UNITS
78  {
79      /** */
80      private static final long serialVersionUID = 1L;
81  
82      /** The model. */
83      private FundamentalDiagramPlotsModel model;
84  
85      /** Create a FundamentalDiagrams simulation. */
86      public FundamentalDiagrams()
87      {
88          try
89          {
90              this.properties.add(new SelectionProperty("CarFollowingModel", "Car following model",
91                      "<html>The car following model determines "
92                              + "the acceleration that a vehicle will make taking into account nearby vehicles, "
93                              + "infrastructural restrictions (e.g. speed limit, curvature of the road) "
94                              + "capabilities of the vehicle and personality of the driver.</html>",
95                      new String[] { "IDM", "IDM+" }, 1, false, 500));
96              this.properties.add(new ProbabilityDistributionProperty("TrafficComposition", "Traffic composition",
97                      "<html>Mix of passenger cars and trucks</html>", new String[] { "passenger car", "truck" },
98                      new Double[] { 0.8, 0.2 }, false, 10));
99          }
100         catch (PropertyException exception)
101         {
102             exception.printStackTrace();
103         }
104     }
105 
106     /** {@inheritDoc} */
107     @Override
108     public final void stopTimersThreads()
109     {
110         super.stopTimersThreads();
111         this.model = null;
112     }
113 
114     /**
115      * Main program.
116      * @param args String[]; the command line arguments (not used)
117      * @throws SimRuntimeException on ???
118      */
119     public static void main(final String[] args) throws SimRuntimeException
120     {
121         // Create the simulation and wrap its panel in a JFrame. It does not get much easier/shorter than this...
122         SwingUtilities.invokeLater(new Runnable()
123         {
124             @Override
125             public void run()
126             {
127                 try
128                 {
129                     FundamentalDiagrams fundamentalDiagrams = new FundamentalDiagrams();
130                     fundamentalDiagrams.buildAnimator(Time.ZERO, Duration.ZERO,
131                             new Duration(3600.0, SECOND), fundamentalDiagrams.getProperties(), null, true);
132                 }
133                 catch (SimRuntimeException | NamingException | OTSSimulationException | PropertyException exception)
134                 {
135                     exception.printStackTrace();
136                 }
137             }
138         });
139     }
140 
141     /** {@inheritDoc} */
142     @Override
143     protected final OTSModelInterface makeModel(final GTUColorer colorer)
144     {
145         this.model = new FundamentalDiagramPlotsModel(this.savedUserModifiedProperties, colorer);
146         return this.model;
147     }
148 
149     /** {@inheritDoc} */
150     @Override
151     protected final void addAnimationToggles()
152     {
153         AnimationToggles.setTextAnimationTogglesStandard(this);
154     }
155 
156     /** {@inheritDoc} */
157     @Override
158     protected final void addTabs(final SimpleSimulatorInterface simulator) throws OTSSimulationException
159     {
160         final int panelsPerRow = 3;
161         TablePanel charts = new TablePanel(4, panelsPerRow);
162         for (int plotNumber = 0; plotNumber < 10; plotNumber++)
163         {
164             Length detectorLocation = new Length(400 + 500 * plotNumber, METER);
165             FundamentalDiagram fd;
166             try
167             {
168                 fd = new FundamentalDiagram("Fundamental Diagram at " + detectorLocation.getSI() + "m", new Duration(1, MINUTE),
169                         this.model.getLane(), detectorLocation, simulator);
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         addTab(getTabCount(), "statistics", 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-2017 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: 2017-04-29 15:37:05 +0200 (Sat, 29 Apr 2017) $, @version $Revision: 3579 $, 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 FundamentalDiagramPlotsModel implements OTSModelInterface, UNITS
218     {
219         /** */
220         private static final long serialVersionUID = 20140820L;
221 
222         /** The simulator. */
223         private OTSDEVSSimulatorInterface simulator;
224 
225         /** The network. */
226         private OTSNetwork network = new OTSNetwork("network");
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 = 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         /** Minimum distance. */
250         private Length minimumDistance = new Length(0, METER);
251 
252         /** Maximum distance. */
253         private Length maximumDistance = new Length(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 List<FundamentalDiagram> fundamentalDiagrams = new ArrayList<>();
263 
264         /** User settable properties. */
265         private List<Property<?>> fundamentalDiagramProperties = 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         FundamentalDiagramPlotsModel(final List<Property<?>> properties, final GTUColorer gtuColorer)
278         {
279             this.fundamentalDiagramProperties = 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             try
289             {
290                 this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
291                 OTSNode from = new OTSNode(this.network, "From", new OTSPoint3D(getMinimumDistance().getSI(), 0, 0));
292                 OTSNode to = new OTSNode(this.network, "To", new OTSPoint3D(getMaximumDistance().getSI(), 0, 0));
293                 OTSNode end = new OTSNode(this.network, "End", new OTSPoint3D(getMaximumDistance().getSI() + 50.0, 0, 0));
294                 Set<GTUType> compatibility = new HashSet<>();
295                 compatibility.add(this.gtuType);
296                 LaneType laneType = new LaneType("CarLane", compatibility);
297                 this.lane = LaneFactory.makeLane(this.network, "Lane", from, to, null, laneType, this.speedLimit,
298                         this.simulator, LongitudinalDirectionality.DIR_PLUS);
299                 CrossSectionLink endLink = LaneFactory.makeLink(this.network, "endLink", to, end, null,
300                         LongitudinalDirectionality.DIR_PLUS, simulator);
301                 // No overtaking, single lane
302                 Lane sinkLane = new Lane(endLink, "sinkLane", this.lane.getLateralCenterPosition(1.0),
303                         this.lane.getLateralCenterPosition(1.0), this.lane.getWidth(1.0), this.lane.getWidth(1.0), laneType,
304                         LongitudinalDirectionality.DIR_PLUS, this.speedLimit, new OvertakingConditions.None());
305                 new SinkSensor(sinkLane, new Length(10.0, METER), this.simulator);
306             }
307             catch (NamingException | NetworkException | OTSGeometryException exception)
308             {
309                 exception.printStackTrace();
310             }
311 
312             // create SinkLane
313 
314             for (Property<?> p : this.fundamentalDiagramProperties)
315             {
316                 if (p instanceof SelectionProperty)
317                 {
318                     SelectionProperty sp = (SelectionProperty) p;
319                     if ("CarFollowingModel".equals(sp.getKey()))
320                     {
321                         String modelName = sp.getValue();
322                         if (modelName.equals("IDM"))
323                         {
324                             this.carFollowingModelCars = new IDMOld(new Acceleration(1, METER_PER_SECOND_2),
325                                     new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
326                                     1d);
327                             this.carFollowingModelTrucks = new IDMOld(new Acceleration(0.5, METER_PER_SECOND_2),
328                                     new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
329                                     1d);
330                         }
331                         else if (modelName.equals("IDM+"))
332                         {
333                             this.carFollowingModelCars = new IDMPlusOld(new Acceleration(1, METER_PER_SECOND_2),
334                                     new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
335                                     1d);
336                             this.carFollowingModelTrucks = new IDMPlusOld(new Acceleration(0.5, METER_PER_SECOND_2),
337                                     new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND),
338                                     1d);
339                         }
340                         else
341                         {
342                             throw new Error("Car following model " + modelName + " not implemented");
343                         }
344                     }
345                     else
346                     {
347                         throw new Error("Unhandled SelectionProperty " + p.getKey());
348                     }
349                 }
350                 else if (p instanceof ProbabilityDistributionProperty)
351                 {
352                     ProbabilityDistributionProperty pdp = (ProbabilityDistributionProperty) p;
353                     String modelName = p.getKey();
354                     if (modelName.equals("TrafficComposition"))
355                     {
356                         this.carProbability = pdp.getValue()[0];
357                     }
358                     else
359                     {
360                         throw new Error("Unhandled ProbabilityDistributionProperty " + p.getKey());
361                     }
362                 }
363                 else
364                 {
365                     throw new Error("Unhandled property: " + p);
366                 }
367             }
368 
369             // 1500 [veh / hour] == 2.4s headway
370             this.headway = new Duration(3600.0 / 1500.0, SECOND);
371 
372             try
373             {
374                 // Schedule creation of the first car (this will re-schedule itself one headway later, etc.).
375                 this.simulator.scheduleEventAbs(Time.ZERO, this, this, "generateCar", null);
376                 // Create a block at t = 5 minutes
377                 this.simulator.scheduleEventAbs(new Time(300, TimeUnit.BASE_SECOND), this, this, "createBlock", null);
378                 // Remove the block at t = 7 minutes
379                 this.simulator.scheduleEventAbs(new Time(420, TimeUnit.BASE_SECOND), this, this, "removeBlock", null);
380                 // Schedule regular updates of the graph
381                 for (int t = 1; t <= 1800; t++)
382                 {
383                     this.simulator.scheduleEventAbs(new Time(t - 0.001, TimeUnit.BASE_SECOND), this, this, "drawGraphs", null);
384                 }
385             }
386             catch (SimRuntimeException exception)
387             {
388                 exception.printStackTrace();
389             }
390         }
391 
392         /**
393          * Set up the block.
394          * @throws RemoteException on communications failure
395          */
396         protected final void createBlock() throws RemoteException
397         {
398             Length initialPosition = new Length(4000, METER);
399             Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
400             try
401             {
402                 initialPositions.add(new DirectedLanePosition(this.getLane(), initialPosition, GTUDirectionality.DIR_PLUS));
403                 BehavioralCharacteristics behavioralCharacteristics = DefaultsFactory.getDefaultBehavioralCharacteristics();
404                 // LaneBasedBehavioralCharacteristics drivingCharacteristics =
405                 // new LaneBasedBehavioralCharacteristics(this.carFollowingModelCars, this.laneChangeModel);
406 
407                 this.block = new LaneBasedIndividualGTU("999999", this.gtuType, new Length(4, METER), new Length(1.8, METER),
408                         Speed.ZERO, this.simulator, this.network);
409                 LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics,
410                         new LaneBasedGTUFollowingTacticalPlanner(this.carFollowingModelCars, this.block), this.block);
411                 this.block.initWithAnimation(strategicalPlanner, initialPositions, Speed.ZERO,
412                         DefaultCarAnimation.class, this.gtuColorer);
413             }
414             catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
415             {
416                 exception.printStackTrace();
417             }
418         }
419 
420         /**
421          * Remove the block.
422          */
423         protected final void removeBlock()
424         {
425             this.block.destroy();
426             this.block = null;
427         }
428 
429         /**
430          * Generate cars at a fixed rate (implemented by re-scheduling this method).
431          */
432         protected final void generateCar()
433         {
434             boolean generateTruck = this.randomGenerator.nextDouble() > this.carProbability;
435             Length initialPosition = new Length(0, METER);
436             Speed initialSpeed = new Speed(100, KM_PER_HOUR);
437             Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
438             try
439             {
440                 initialPositions.add(new DirectedLanePosition(this.getLane(), initialPosition, GTUDirectionality.DIR_PLUS));
441                 Length vehicleLength = new Length(generateTruck ? 15 : 4, METER);
442                 GTUFollowingModelOld gtuFollowingModel =
443                         generateTruck ? this.carFollowingModelTrucks : this.carFollowingModelCars;
444                 if (null == gtuFollowingModel)
445                 {
446                     throw new Error("gtuFollowingModel is null");
447                 }
448                 BehavioralCharacteristics behavioralCharacteristics = DefaultsFactory.getDefaultBehavioralCharacteristics();
449                 // LaneBasedBehavioralCharacteristics drivingCharacteristics =
450                 // new LaneBasedBehavioralCharacteristics(gtuFollowingModel, this.laneChangeModel);
451 
452                 LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU("" + (++this.carsCreated), this.gtuType, vehicleLength,
453                         new Length(1.8, METER), new Speed(200, KM_PER_HOUR), this.simulator, this.network);
454                 LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics,
455                         new LaneBasedGTUFollowingTacticalPlanner(gtuFollowingModel, gtu), gtu);
456                 gtu.initWithAnimation(strategicalPlanner, initialPositions, initialSpeed, DefaultCarAnimation.class,
457                         this.gtuColorer);
458 
459                 this.simulator.scheduleEventRel(this.headway, this, this, "generateCar", null);
460             }
461             catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
462             {
463                 exception.printStackTrace();
464             }
465         }
466 
467         /**
468         * 
469         */
470         protected final void drawGraphs()
471         {
472             // Notify the Fundamental Diagram plots that the underlying data has changed
473             for (FundamentalDiagram fd : this.fundamentalDiagrams)
474             {
475                 fd.reGraph();
476             }
477         }
478 
479         /** {@inheritDoc} */
480         @Override
481         public final SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator() throws RemoteException
482         {
483             return this.simulator;
484         }
485 
486         /** {@inheritDoc} */
487         @Override
488         public OTSNetwork getNetwork()
489         {
490             return this.network;
491         }
492 
493         /**
494          * @return fundamentalDiagramPlots
495          */
496         public final List<FundamentalDiagram> getFundamentalDiagrams()
497         {
498             return this.fundamentalDiagrams;
499         }
500 
501         /**
502          * @return minimumDistance
503          */
504         public final Length getMinimumDistance()
505         {
506             return this.minimumDistance;
507         }
508 
509         /**
510          * @return maximumDistance
511          */
512         public final Length getMaximumDistance()
513         {
514             return this.maximumDistance;
515         }
516 
517         /**
518          * @return lane.
519          */
520         public Lane getLane()
521         {
522             return this.lane;
523         }
524     }
525 
526     /** {@inheritDoc} */
527     @Override
528     public final String toString()
529     {
530         return "FundamentalDiagrams [model=" + this.model + "]";
531     }
532 }