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