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