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.TrajectoryPlot;
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 Trajectories 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 Trajectories extends AbstractWrappableAnimation implements UNITS
78  {
79      /** */
80      private static final long serialVersionUID = 1L;
81  
82      /** The model. */
83      private TrajectoriesModel model;
84  
85      /** Create a Trajectories simulation. */
86      public Trajectories()
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, 10));
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, 9));
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                     Trajectories trajectories = new Trajectories();
130                     trajectories.buildAnimator(Time.ZERO, Duration.ZERO, new Duration(3600.0, SECOND),
131                             trajectories.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 void addAnimationToggles()
144     {
145         AnimationToggles.setTextAnimationTogglesStandard(this);
146     }
147 
148     /** {@inheritDoc} */
149     @Override
150     protected final OTSModelInterface makeModel(final GTUColorer colorer)
151     {
152         this.model = new TrajectoriesModel(this.savedUserModifiedProperties, colorer);
153         return this.model;
154     }
155 
156     /** {@inheritDoc} */
157     @Override
158     protected final void addTabs(final SimpleSimulatorInterface simulator) throws OTSSimulationException
159     {
160         TablePanel charts = new TablePanel(1, 1);
161         Duration sampleInterval = new Duration(0.5, SECOND);
162         List<Lane> path = new ArrayList<>();
163         path.add(this.model.getLane());
164         TrajectoryPlot tp = new TrajectoryPlot("Trajectory Plot", sampleInterval, path, simulator);
165         tp.setTitle("Density Contour Graph");
166         tp.setExtendedState(Frame.MAXIMIZED_BOTH);
167         this.model.setTrajectoryPlot(tp);
168         charts.setCell(tp.getContentPane(), 0, 0);
169         addTab(getTabCount(), "statistics", charts);
170     }
171 
172     /** {@inheritDoc} */
173     @Override
174     public final String shortName()
175     {
176         return "Trajectory plot";
177     }
178 
179     /** {@inheritDoc} */
180     @Override
181     public final String description()
182     {
183         return "<html><H1>Trajectories</H1>"
184                 + "Simulation of a single lane road of 5 km length. Vechicles are generated at a constant rate of "
185                 + "1500 veh/hour. At time 300s a blockade is inserted at position 4km; this blockade is removed at time "
186                 + "420s. This blockade simulates a bridge opening.<br>"
187                 + "The blockade causes a traffic jam that slowly dissolves after the blockade is removed.<br>"
188                 + "Output is a Trajectory plots.</html>";
189     }
190 
191 }
192 
193 /**
194  * Simulate a single lane road of 5 km length. Vehicles are generated at a constant rate of 1500 veh/hour. At time 300s a
195  * blockade is inserted at position 4 km; this blockade is removed at time 500s. The used car following algorithm is IDM+
196  * <a href="http://opentrafficsim.org/downloads/MOTUS%20reference.pdf"><i>Integrated Lane Change Model with Relaxation and
197  * Synchronization</i>, by Wouter J. Schakel, Victor L. Knoop and Bart van Arem, 2012</a>. <br>
198  * Output is a trajectory plot with simulation time along the horizontal axis and distance along the road along the vertical
199  * axis.
200  * <p>
201  * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
202  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
203  * <p>
204  * $LastChangedDate: 2017-04-29 15:37:05 +0200 (Sat, 29 Apr 2017) $, @version $Revision: 3579 $, by $Author: averbraeck $,
205  * initial version ug 1, 2014 <br>
206  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
207  */
208 class TrajectoriesModel implements OTSModelInterface, UNITS
209 {
210     /** */
211     private static final long serialVersionUID = 20140815L;
212 
213     /** The simulator. */
214     private OTSDEVSSimulatorInterface simulator;
215 
216     /** The network. */
217     private OTSNetwork network = new OTSNetwork("network");
218 
219     /** The headway (inter-vehicle time). */
220     private Duration headway;
221 
222     /** Number of cars created. */
223     private int carsCreated = 0;
224 
225     /** Type of all GTUs. */
226     private GTUType gtuType = CAR;
227 
228     /** The car following model, e.g. IDM Plus for cars. */
229     private GTUFollowingModelOld carFollowingModelCars;
230 
231     /** The car following model, e.g. IDM Plus for trucks. */
232     private GTUFollowingModelOld carFollowingModelTrucks;
233 
234     /** The probability that the next generated GTU is a passenger car. */
235     private double carProbability;
236 
237     /** The blocking car. */
238     private LaneBasedIndividualGTU block = null;
239 
240     /** Minimum distance. */
241     private Length minimumDistance = new Length(0, METER);
242 
243     /** Maximum distance. */
244     private Length maximumDistance = new Length(5000, METER);
245 
246     /** The Lane containing the simulated Cars. */
247     private Lane lane;
248 
249     /** The speed limit. */
250     private Speed speedLimit = new Speed(100, KM_PER_HOUR);
251 
252     /** The trajectory plot. */
253     private TrajectoryPlot trajectoryPlot;
254 
255     /** User settable properties. */
256     private List<Property<?>> properties = null;
257 
258     /** The random number generator used to decide what kind of GTU to generate. */
259     private Random randomGenerator = new Random(12345);
260 
261     /** The GTUColorer for the generated vehicles. */
262     private final GTUColorer gtuColorer;
263 
264     /**
265      * @param properties ArrayList&lt;AbstractProperty&lt;?&gt;&gt;; the properties
266      * @param gtuColorer the default and initial GTUColorer, e.g. a DefaultSwitchableTUColorer.
267      */
268     TrajectoriesModel(final List<Property<?>> properties, final GTUColorer gtuColorer)
269     {
270         this.properties = properties;
271         this.gtuColorer = gtuColorer;
272     }
273 
274     /** {@inheritDoc} */
275     @Override
276     public final void constructModel(final SimulatorInterface<Time, Duration, OTSSimTimeDouble> theSimulator)
277             throws SimRuntimeException, RemoteException
278     {
279         this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
280         try
281         {
282             OTSNode from = new OTSNode(this.network, "From", new OTSPoint3D(getMinimumDistance().getSI(), 0, 0));
283             OTSNode to = new OTSNode(this.network, "To", new OTSPoint3D(getMaximumDistance().getSI(), 0, 0));
284             OTSNode end = new OTSNode(this.network, "End", new OTSPoint3D(getMaximumDistance().getSI() + 50.0, 0, 0));
285             Set<GTUType> compatibility = new HashSet<>();
286             compatibility.add(this.gtuType);
287             LaneType laneType = new LaneType("CarLane", compatibility);
288             this.lane = LaneFactory.makeLane(this.network, "Lane", from, to, null, laneType, this.speedLimit, this.simulator,
289                     LongitudinalDirectionality.DIR_PLUS);
290             CrossSectionLink endLink =
291                     LaneFactory.makeLink(this.network, "endLink", to, end, null, LongitudinalDirectionality.DIR_PLUS, simulator);
292             // No overtaking, single (sink) lane
293             Lane sinkLane = new Lane(endLink, "sinkLane", this.lane.getLateralCenterPosition(1.0),
294                     this.lane.getLateralCenterPosition(1.0), this.lane.getWidth(1.0), this.lane.getWidth(1.0), laneType,
295                     LongitudinalDirectionality.DIR_PLUS, this.speedLimit, new OvertakingConditions.None());
296             new SinkSensor(sinkLane, new Length(10.0, METER), this.simulator);
297         }
298         catch (NamingException | NetworkException | OTSGeometryException exception1)
299         {
300             exception1.printStackTrace();
301         }
302 
303         for (Property<?> p : this.properties)
304         {
305             if (p instanceof SelectionProperty)
306             {
307                 SelectionProperty sp = (SelectionProperty) p;
308                 if ("CarFollowingModel".equals(sp.getKey()))
309                 {
310                     String modelName = sp.getValue();
311                     if (modelName.equals("IDM"))
312                     {
313                         this.carFollowingModelCars = new IDMOld(new Acceleration(1, METER_PER_SECOND_2),
314                                 new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND), 1d);
315                         this.carFollowingModelTrucks = new IDMOld(new Acceleration(0.5, METER_PER_SECOND_2),
316                                 new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND), 1d);
317                     }
318                     else if (modelName.equals("IDM+"))
319                     {
320                         this.carFollowingModelCars = new IDMPlusOld(new Acceleration(1, METER_PER_SECOND_2),
321                                 new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND), 1d);
322                         this.carFollowingModelTrucks = new IDMPlusOld(new Acceleration(0.5, METER_PER_SECOND_2),
323                                 new Acceleration(1.5, METER_PER_SECOND_2), new Length(2, METER), new Duration(1, SECOND), 1d);
324                     }
325                     else
326                     {
327                         throw new Error("Car following model " + modelName + " not implemented");
328                     }
329                 }
330                 else
331                 {
332                     throw new Error("Unhandled SelectionProperty " + p.getKey());
333                 }
334             }
335             else if (p instanceof ProbabilityDistributionProperty)
336             {
337                 ProbabilityDistributionProperty pdp = (ProbabilityDistributionProperty) p;
338                 String modelName = p.getKey();
339                 if (modelName.equals("TrafficComposition"))
340                 {
341                     this.carProbability = pdp.getValue()[0];
342                 }
343                 else
344                 {
345                     throw new Error("Unhandled ProbabilityDistributionProperty " + p.getKey());
346                 }
347             }
348             else
349             {
350                 throw new Error("Unhandled property: " + p);
351             }
352         }
353 
354         // 1500 [vehicles / hour] == 2.4s headway
355         this.headway = new Duration(3600.0 / 1500.0, SECOND);
356 
357         try
358         {
359             // Schedule creation of the first car (this will re-schedule itself one headway later, etc.).
360             this.simulator.scheduleEventAbs(Time.ZERO, this, this, "generateCar", null);
361             // Create a block at t = 5 minutes
362             this.simulator.scheduleEventAbs(new Time(300, TimeUnit.BASE_SECOND), this, this, "createBlock", null);
363             // Remove the block at t = 7 minutes
364             this.simulator.scheduleEventAbs(new Time(420, TimeUnit.BASE_SECOND), this, this, "removeBlock", null);
365             // Schedule regular updates of the graph
366             for (int t = 1; t <= 1800; t++)
367             {
368                 this.simulator.scheduleEventAbs(new Time(t - 0.001, TimeUnit.BASE_SECOND), this, this, "drawGraph", null);
369             }
370         }
371         catch (SimRuntimeException exception)
372         {
373             exception.printStackTrace();
374         }
375     }
376 
377     /**
378      * Set up the block.
379      * @throws NamingException on error during adding of animation handler
380      * @throws SimRuntimeException on ???
381      * @throws NetworkException on network inconsistency
382      * @throws GTUException if creation of the GTU fails
383      * @throws OTSGeometryException when the initial position is not on the cecnter line of the lane
384      */
385     protected final void createBlock()
386             throws NamingException, SimRuntimeException, NetworkException, GTUException, OTSGeometryException
387     {
388         Length initialPosition = new Length(4000, METER);
389         Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
390         initialPositions.add(new DirectedLanePosition(this.getLane(), initialPosition, GTUDirectionality.DIR_PLUS));
391         BehavioralCharacteristics behavioralCharacteristics = DefaultsFactory.getDefaultBehavioralCharacteristics();
392         this.block = new LaneBasedIndividualGTU("999999", this.gtuType, new Length(4, METER), new Length(1.8, METER),
393                 Speed.ZERO, this.simulator, this.network);
394         LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics,
395                 new LaneBasedGTUFollowingTacticalPlanner(this.carFollowingModelCars, this.block), this.block);
396         this.block.initWithAnimation(strategicalPlanner, initialPositions, Speed.ZERO,
397                 DefaultCarAnimation.class, this.gtuColorer);
398     }
399 
400     /**
401      * Remove the block.
402      */
403     protected final void removeBlock()
404     {
405         this.block.destroy();
406         this.block = null;
407     }
408 
409     /**
410      * Generate cars at a fixed rate (implemented by re-scheduling this method).
411      */
412     protected final void generateCar()
413     {
414         boolean generateTruck = this.randomGenerator.nextDouble() > this.carProbability;
415         Length initialPosition = new Length(0, METER);
416         Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
417         try
418         {
419             initialPositions.add(new DirectedLanePosition(this.getLane(), initialPosition, GTUDirectionality.DIR_PLUS));
420             Speed initialSpeed = new Speed(100, KM_PER_HOUR);
421             Length vehicleLength = new Length(generateTruck ? 15 : 4, METER);
422             GTUFollowingModelOld gtuFollowingModel = generateTruck ? this.carFollowingModelTrucks : this.carFollowingModelCars;
423             if (null == gtuFollowingModel)
424             {
425                 throw new Error("gtuFollowingModel is null");
426             }
427             BehavioralCharacteristics behavioralCharacteristics = DefaultsFactory.getDefaultBehavioralCharacteristics();
428             LaneBasedIndividualGTU gtu = new LaneBasedIndividualGTU("" + (++this.carsCreated), this.gtuType, vehicleLength,
429                     new Length(1.8, METER), new Speed(200, KM_PER_HOUR), this.simulator, this.network);
430             LaneBasedStrategicalPlanner strategicalPlanner = new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics,
431                     new LaneBasedGTUFollowingTacticalPlanner(gtuFollowingModel, gtu), gtu);
432             gtu.initWithAnimation(strategicalPlanner, initialPositions, initialSpeed, DefaultCarAnimation.class,
433                     this.gtuColorer);
434             // Re-schedule this method after headway seconds
435             this.simulator.scheduleEventRel(this.headway, this, this, "generateCar", null);
436         }
437         catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
438         {
439             exception.printStackTrace();
440         }
441     }
442 
443     /** {@inheritDoc} */
444     @Override
445     public final SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator() throws RemoteException
446     {
447         return this.simulator;
448     }
449 
450     /** {@inheritDoc} */
451     @Override
452     public OTSNetwork getNetwork()
453     {
454         return this.network;
455     }
456 
457     /**
458      * Notify the contour plots that the underlying data has changed.
459      */
460     protected final void drawGraph()
461     {
462         this.trajectoryPlot.reGraph();
463     }
464 
465     /**
466      * @return minimum distance of the simulation
467      */
468     public final Length getMinimumDistance()
469     {
470         return this.minimumDistance;
471     }
472 
473     /**
474      * @return maximum distance of the simulation
475      */
476     public final Length getMaximumDistance()
477     {
478         return this.maximumDistance;
479     }
480 
481     /**
482      * @param trajectoryPlot TrajectoryPlot
483      */
484     public final void setTrajectoryPlot(final TrajectoryPlot trajectoryPlot)
485     {
486         this.trajectoryPlot = trajectoryPlot;
487     }
488 
489     /**
490      * @return lane.
491      */
492     public Lane getLane()
493     {
494         return this.lane;
495     }
496 
497 }