View Javadoc
1   package org.opentrafficsim.demo.carFollowing;
2   
3   import java.awt.Container;
4   import java.awt.Frame;
5   import java.awt.geom.Rectangle2D;
6   import java.io.IOException;
7   import java.net.URL;
8   import java.rmi.RemoteException;
9   import java.util.ArrayList;
10  import java.util.HashSet;
11  import java.util.LinkedHashSet;
12  import java.util.List;
13  import java.util.Random;
14  import java.util.Set;
15  
16  import javax.naming.NamingException;
17  import javax.swing.JComponent;
18  import javax.swing.JPanel;
19  import javax.swing.JScrollPane;
20  import javax.swing.SwingUtilities;
21  
22  import org.djunits.unit.AccelerationUnit;
23  import org.djunits.unit.LengthUnit;
24  import org.djunits.unit.TimeUnit;
25  import org.djunits.unit.UNITS;
26  import org.djunits.value.vdouble.scalar.Acceleration;
27  import org.djunits.value.vdouble.scalar.Duration;
28  import org.djunits.value.vdouble.scalar.Length;
29  import org.djunits.value.vdouble.scalar.Speed;
30  import org.djunits.value.vdouble.scalar.Time;
31  import org.opentrafficsim.base.modelproperties.BooleanProperty;
32  import org.opentrafficsim.base.modelproperties.CompoundProperty;
33  import org.opentrafficsim.base.modelproperties.ProbabilityDistributionProperty;
34  import org.opentrafficsim.base.modelproperties.Property;
35  import org.opentrafficsim.base.modelproperties.PropertyException;
36  import org.opentrafficsim.base.modelproperties.SelectionProperty;
37  import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
38  import org.opentrafficsim.core.dsol.OTSModelInterface;
39  import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
40  import org.opentrafficsim.core.geometry.OTSGeometryException;
41  import org.opentrafficsim.core.geometry.OTSPoint3D;
42  import org.opentrafficsim.core.gtu.GTUDirectionality;
43  import org.opentrafficsim.core.gtu.GTUException;
44  import org.opentrafficsim.core.gtu.GTUType;
45  import org.opentrafficsim.core.gtu.animation.GTUColorer;
46  import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
47  import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterException;
48  import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypes;
49  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan;
50  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan.Segment;
51  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
52  import org.opentrafficsim.core.network.LongitudinalDirectionality;
53  import org.opentrafficsim.core.network.NetworkException;
54  import org.opentrafficsim.core.network.OTSNetwork;
55  import org.opentrafficsim.core.network.OTSNode;
56  import org.opentrafficsim.graphs.AccelerationContourPlot;
57  import org.opentrafficsim.graphs.ContourPlot;
58  import org.opentrafficsim.graphs.DensityContourPlot;
59  import org.opentrafficsim.graphs.FlowContourPlot;
60  import org.opentrafficsim.graphs.LaneBasedGTUSampler;
61  import org.opentrafficsim.graphs.SpeedContourPlot;
62  import org.opentrafficsim.graphs.TrajectoryPlot;
63  import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
64  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
65  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
66  import org.opentrafficsim.road.gtu.lane.perception.categories.DefaultSimplePerception;
67  import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
68  import org.opentrafficsim.road.gtu.lane.tactical.AbstractLaneBasedTacticalPlanner;
69  import org.opentrafficsim.road.gtu.lane.tactical.LanePathInfo;
70  import org.opentrafficsim.road.gtu.lane.tactical.following.AccelerationStep;
71  import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
72  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMOld;
73  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
74  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
75  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
76  import org.opentrafficsim.road.modelproperties.IDMPropertySet;
77  import org.opentrafficsim.road.network.factory.LaneFactory;
78  import org.opentrafficsim.road.network.lane.CrossSectionLink;
79  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
80  import org.opentrafficsim.road.network.lane.Lane;
81  import org.opentrafficsim.road.network.lane.LaneType;
82  import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
83  import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
84  import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
85  import org.opentrafficsim.simulationengine.OTSSimulationException;
86  import org.opentrafficsim.simulationengine.SimpleSimulatorInterface;
87  
88  import nl.tudelft.simulation.dsol.SimRuntimeException;
89  import nl.tudelft.simulation.dsol.gui.swing.HTMLPanel;
90  import nl.tudelft.simulation.dsol.gui.swing.TablePanel;
91  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
92  import nl.tudelft.simulation.jstats.distributions.DistContinuous;
93  import nl.tudelft.simulation.jstats.distributions.DistTriangular;
94  import nl.tudelft.simulation.jstats.streams.MersenneTwister;
95  import nl.tudelft.simulation.language.d3.DirectedPoint;
96  
97  /**
98   * Simplest contour plots demonstration.
99   * <p>
100  * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
101  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
102  * <p>
103  * $LastChangedDate: 2016-01-05 06:14:49 +0100 (Tue, 05 Jan 2016) $, @version $Revision: 1685 $, by $Author: averbraeck $,
104  * initial version 12 nov. 2014 <br>
105  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
106  */
107 public class StraightPerception extends AbstractWrappableAnimation implements UNITS
108 {
109     /** */
110     private static final long serialVersionUID = 1L;
111 
112     /** The model. */
113     private StraightPerceptionModel model;
114 
115     /**
116      * Create a ContourPlots simulation.
117      * @throws PropertyException when the provided properties could not be handled
118      */
119     public StraightPerception() throws PropertyException
120     {
121         List<Property<?>> outputProperties = new ArrayList<>();
122         outputProperties.add(new BooleanProperty("DensityPlot", "Density", "Density contour plot", true, false, 0));
123         outputProperties.add(new BooleanProperty("FlowPlot", "Flow", "Flow contour plot", true, false, 1));
124         outputProperties.add(new BooleanProperty("SpeedPlot", "Speed", "Speed contour plot", true, false, 2));
125         outputProperties.add(new BooleanProperty("AccelerationPlot", "Acceleration", "Acceleration contour plot", true, false,
126                 3));
127         outputProperties.add(new BooleanProperty("TrajectoryPlot", "Trajectories", "Trajectory (time/distance) diagram", true,
128                 false, 4));
129         this.properties.add(new CompoundProperty("OutputGraphs", "Output graphs", "Select the graphical output",
130                 outputProperties, true, 1000));
131     }
132 
133     /** {@inheritDoc} */
134     @Override
135     public final void stopTimersThreads()
136     {
137         super.stopTimersThreads();
138         this.model = null;
139     }
140 
141     /**
142      * Main program.
143      * @param args String[]; the command line arguments (not used)
144      * @throws SimRuntimeException when simulation cannot be created with given parameters
145      */
146     public static void main(final String[] args) throws SimRuntimeException
147     {
148         SwingUtilities.invokeLater(new Runnable()
149         {
150             @SuppressWarnings("synthetic-access")
151             @Override
152             public void run()
153             {
154                 try
155                 {
156                     StraightPerception straight = new StraightPerception();
157                     List<Property<?>> localProperties = straight.getProperties();
158                     try
159                     {
160                         localProperties.add(new ProbabilityDistributionProperty("TrafficComposition", "Traffic composition",
161                                 "<html>Mix of passenger cars and trucks</html>", new String[] { "passenger car", "truck" },
162                                 new Double[] { 0.8, 0.2 }, false, 10));
163                     }
164                     catch (PropertyException exception)
165                     {
166                         exception.printStackTrace();
167                     }
168                     localProperties.add(new SelectionProperty("CarFollowingModel", "Car following model",
169                             "<html>The car following model determines "
170                                     + "the acceleration that a vehicle will make taking into account "
171                                     + "nearby vehicles, infrastructural restrictions (e.g. speed limit, "
172                                     + "curvature of the road) capabilities of the vehicle and personality "
173                                     + "of the driver.</html>", new String[] { "IDM", "IDM+" }, 1, false, 1));
174                     localProperties.add(IDMPropertySet.makeIDMPropertySet("IDMCar", "Car", new Acceleration(1.0,
175                             METER_PER_SECOND_2), new Acceleration(1.5, METER_PER_SECOND_2), new Length(2.0, METER),
176                             new Duration(1.0, SECOND), 2));
177                     localProperties.add(IDMPropertySet.makeIDMPropertySet("IDMTruck", "Truck", new Acceleration(0.5,
178                             METER_PER_SECOND_2), new Acceleration(1.25, METER_PER_SECOND_2), new Length(2.0, METER),
179                             new Duration(1.0, SECOND), 3));
180                     straight.buildAnimator(new Time(0.0, SECOND), new Duration(0.0, SECOND), new Duration(3600.0, SECOND),
181                             localProperties, null, true);
182                     straight.panel.getTabbedPane().addTab("info", straight.makeInfoPane());
183                 }
184                 catch (SimRuntimeException | NamingException | OTSSimulationException | PropertyException exception)
185                 {
186                     exception.printStackTrace();
187                 }
188             }
189         });
190     }
191 
192     /** {@inheritDoc} */
193     @Override
194     protected final Rectangle2D.Double makeAnimationRectangle()
195     {
196         return new Rectangle2D.Double(0, -100, 5000, 200);
197     }
198 
199     /** {@inheritDoc} */
200     @Override
201     protected final OTSModelInterface makeModel(final GTUColorer colorer)
202     {
203         this.model = new StraightPerceptionModel(this.savedUserModifiedProperties, colorer);
204         return this.model;
205     }
206 
207     /**
208      * @return an info pane to be added to the tabbed pane.
209      */
210     protected final JComponent makeInfoPane()
211     {
212         // Make the info tab
213         String helpSource = "/" + StraightPerceptionModel.class.getPackage().getName().replace('.', '/') + "/IDMPlus.html";
214         URL page = StraightPerceptionModel.class.getResource(helpSource);
215         if (page != null)
216         {
217             try
218             {
219                 HTMLPanel htmlPanel = new HTMLPanel(page);
220                 return new JScrollPane(htmlPanel);
221             }
222             catch (IOException exception)
223             {
224                 exception.printStackTrace();
225             }
226         }
227         return new JPanel();
228     }
229 
230     /** {@inheritDoc} */
231     @Override
232     protected final JPanel makeCharts(SimpleSimulatorInterface simulator) throws OTSSimulationException, PropertyException
233     {
234 
235         // Make the tab with the plots
236         Property<?> output = new CompoundProperty("", "", "", this.properties, false, 0).findByKey("OutputGraphs");
237         if (null == output)
238         {
239             throw new Error("Cannot find output properties");
240         }
241         ArrayList<BooleanProperty> graphs = new ArrayList<>();
242         if (output instanceof CompoundProperty)
243         {
244             CompoundProperty outputProperties = (CompoundProperty) output;
245             for (Property<?> ap : outputProperties.getValue())
246             {
247                 if (ap instanceof BooleanProperty)
248                 {
249                     BooleanProperty bp = (BooleanProperty) ap;
250                     if (bp.getValue())
251                     {
252                         graphs.add(bp);
253                     }
254                 }
255             }
256         }
257         else
258         {
259             throw new Error("output properties should be compound");
260         }
261         int graphCount = graphs.size();
262         int columns = (int) Math.ceil(Math.sqrt(graphCount));
263         int rows = 0 == columns ? 0 : (int) Math.ceil(graphCount * 1.0 / columns);
264         TablePanel charts = new TablePanel(columns, rows);
265 
266         for (int i = 0; i < graphCount; i++)
267         {
268             String graphName = graphs.get(i).getKey();
269             Container container = null;
270             LaneBasedGTUSampler graph;
271             if (graphName.contains("Trajectories"))
272             {
273                 List<Lane> path = new ArrayList<>();
274                 path.add(this.model.getLane());
275                 TrajectoryPlot tp = new TrajectoryPlot("TrajectoryPlot", new Duration(0.5, SECOND), path, simulator);
276                 tp.setTitle("Trajectory Graph");
277                 tp.setExtendedState(Frame.MAXIMIZED_BOTH);
278                 graph = tp;
279                 container = tp.getContentPane();
280             }
281             else
282             {
283                 ContourPlot cp;
284                 if (graphName.contains("DensityPlot"))
285                 {
286                     cp = new DensityContourPlot("DensityPlot", this.model.getPath());
287                     cp.setTitle("Density Contour Graph");
288                 }
289                 else if (graphName.contains("SpeedPlot"))
290                 {
291                     cp = new SpeedContourPlot("SpeedPlot", this.model.getPath());
292                     cp.setTitle("Speed Contour Graph");
293                 }
294                 else if (graphName.contains("FlowPlot"))
295                 {
296                     cp = new FlowContourPlot("FlowPlot", this.model.getPath());
297                     cp.setTitle("Flow Contour Graph");
298                 }
299                 else if (graphName.contains("AccelerationPlot"))
300                 {
301                     cp = new AccelerationContourPlot("AccelerationPlot", this.model.getPath());
302                     cp.setTitle("Acceleration Contour Graph");
303                 }
304                 else
305                 {
306                     throw new Error("Unhandled type of contourplot: " + graphName);
307                 }
308                 graph = cp;
309                 container = cp.getContentPane();
310             }
311             // Add the container to the matrix
312             charts.setCell(container, i % columns, i / columns);
313             this.model.getPlots().add(graph);
314         }
315         return charts;
316     }
317 
318     /** {@inheritDoc} */
319     @Override
320     public final String shortName()
321     {
322         return "Straight lane";
323     }
324 
325     /** {@inheritDoc} */
326     @Override
327     public final String description()
328     {
329         return "<html><h1>Simulation of a straight one-lane road with opening bridge</H1>"
330                 + "Simulation of a single lane road of 5 km length. Vehicles are generated at a constant rate of "
331                 + "1500 veh/hour. At time 300s a blockade is inserted at position 4km; this blockade is removed at "
332                 + "time 420s. This blockade simulates a bridge opening.<br>"
333                 + "The blockade causes a traffic jam that slowly dissolves after the blockade is removed.<br>"
334                 + "Selected trajectory and contour plots are generated during the simulation.</html>";
335     }
336 
337 }
338 
339 /**
340  * Simulate a single lane road of 5 km length. Vehicles are generated at a constant rate of 1500 veh/hour. At time 300s a
341  * blockade is inserted at position 4 km; this blockade is removed at time 500s. The used car following algorithm is IDM+ <a
342  * href="http://opentrafficsim.org/downloads/MOTUS%20reference.pdf"><i>Integrated Lane Change Model with Relaxation and
343  * Synchronization</i>, by Wouter J. Schakel, Victor L. Knoop and Bart van Arem, 2012</a>. <br>
344  * Output is a set of block charts:
345  * <ul>
346  * <li>Traffic density</li>
347  * <li>Speed</li>
348  * <li>Flow</li>
349  * <li>Acceleration</li>
350  * </ul>
351  * All these graphs display simulation time along the horizontal axis and distance along the road along the vertical axis.
352  * <p>
353  * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
354  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
355  * <p>
356  * $LastChangedDate: 2016-01-05 06:14:49 +0100 (Tue, 05 Jan 2016) $, @version $Revision: 1685 $, by $Author: averbraeck $,
357  * initial version ug 1, 2014 <br>
358  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
359  */
360 class StraightPerceptionModel implements OTSModelInterface, UNITS
361 {
362     /** */
363     private static final long serialVersionUID = 20140815L;
364 
365     /** The simulator. */
366     private OTSDEVSSimulatorInterface simulator;
367 
368     /** The network. */
369     private OTSNetwork network = new OTSNetwork("network");
370 
371     /** The headway (inter-vehicle time). */
372     private Duration headway;
373 
374     /** Number of cars created. */
375     private int carsCreated = 0;
376 
377     /** Type of all GTUs. */
378     private GTUType gtuType = new GTUType("Car");
379 
380     /** The car following model, e.g. IDM Plus for cars. */
381     private GTUFollowingModelOld carFollowingModelCars;
382 
383     /** The probability that the next generated GTU is a passenger car. */
384     private double carProbability;
385 
386     /** The blocking car. */
387     private LaneBasedIndividualGTU block = null;
388 
389     /** Minimum distance. */
390     private Length minimumDistance = new Length(0, METER);
391 
392     /** Maximum distance. */
393     private Length maximumDistance = new Length(5000, METER);
394 
395     /** The Lane that contains the simulated Cars. */
396     private Lane lane;
397 
398     /** The contour plots. */
399     private List<LaneBasedGTUSampler> plots = new ArrayList<>();
400 
401     /** User settable properties. */
402     private List<Property<?>> properties = null;
403 
404     /** The random number generator used to decide what kind of GTU to generate. */
405     private Random randomGenerator = new Random(12345);
406 
407     /** The GTUColorer for the generated vehicles. */
408     private final GTUColorer gtuColorer;
409 
410     /**
411      * @param properties the user settable properties
412      * @param gtuColorer the default and initial GTUColorer, e.g. a DefaultSwitchableTUColorer.
413      */
414     StraightPerceptionModel(final List<Property<?>> properties, final GTUColorer gtuColorer)
415     {
416         this.properties = properties;
417         this.gtuColorer = gtuColorer;
418     }
419 
420     /** The sequence of Lanes that all vehicles will follow. */
421     private List<Lane> path = new ArrayList<>();
422 
423     /** The speed limit on all Lanes. */
424     private Speed speedLimit = new Speed(100, KM_PER_HOUR);
425 
426     /** The perception interval distribution. */
427     @SuppressWarnings("visibilitymodifier")
428     DistContinuous perceptionIntervalDist = new DistTriangular(new MersenneTwister(2), 0.25, 1, 2);
429 
430     /** The forward headway distribution. */
431     @SuppressWarnings("visibilitymodifier")
432     DistContinuous forwardHeadwayDist = new DistTriangular(new MersenneTwister(20), 20, 50, 100);
433 
434     /**
435      * @return List&lt;Lane&gt;; the set of lanes for the specified index
436      */
437     public List<Lane> getPath()
438     {
439         return new ArrayList<>(this.path);
440     }
441 
442     /** {@inheritDoc} */
443     @Override
444     public final void constructModel(final SimulatorInterface<Time, Duration, OTSSimTimeDouble> theSimulator)
445             throws SimRuntimeException, RemoteException
446     {
447         this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
448         try
449         {
450             OTSNode from = new OTSNode(this.network, "From", new OTSPoint3D(getMinimumDistance().getSI(), 0, 0));
451             OTSNode to = new OTSNode(this.network, "To", new OTSPoint3D(getMaximumDistance().getSI(), 0, 0));
452             OTSNode end = new OTSNode(this.network, "End", new OTSPoint3D(getMaximumDistance().getSI() + 50.0, 0, 0));
453             Set<GTUType> compatibility = new HashSet<>();
454             compatibility.add(this.gtuType);
455             LaneType laneType = new LaneType("CarLane", compatibility);
456             this.lane =
457                     LaneFactory.makeLane(this.network, "Lane", from, to, null, laneType, this.speedLimit, this.simulator,
458                             LongitudinalDirectionality.DIR_PLUS);
459             this.path.add(this.lane);
460             CrossSectionLink endLink =
461                     LaneFactory.makeLink(this.network, "endLink", to, end, null, LongitudinalDirectionality.DIR_PLUS);
462             // No overtaking, single lane
463             Lane sinkLane =
464                     new Lane(endLink, "sinkLane", this.lane.getLateralCenterPosition(1.0),
465                             this.lane.getLateralCenterPosition(1.0), this.lane.getWidth(1.0), this.lane.getWidth(1.0),
466                             laneType, LongitudinalDirectionality.DIR_PLUS, this.speedLimit, new OvertakingConditions.None());
467             new SinkSensor(sinkLane, new Length(10.0, METER), this.simulator);
468             String carFollowingModelName = null;
469             CompoundProperty propertyContainer = new CompoundProperty("", "", "", this.properties, false, 0);
470             Property<?> cfmp = propertyContainer.findByKey("CarFollowingModel");
471             if (null == cfmp)
472             {
473                 throw new Error("Cannot find \"Car following model\" property");
474             }
475             if (cfmp instanceof SelectionProperty)
476             {
477                 carFollowingModelName = ((SelectionProperty) cfmp).getValue();
478             }
479             else
480             {
481                 throw new Error("\"Car following model\" property has wrong type");
482             }
483             for (Property<?> ap : new CompoundProperty("", "", "", this.properties, false, 0))
484             {
485                 if (ap instanceof SelectionProperty)
486                 {
487                     SelectionProperty sp = (SelectionProperty) ap;
488                     if ("CarFollowingModel".equals(sp.getKey()))
489                     {
490                         carFollowingModelName = sp.getValue();
491                     }
492                 }
493                 else if (ap instanceof ProbabilityDistributionProperty)
494                 {
495                     ProbabilityDistributionProperty pdp = (ProbabilityDistributionProperty) ap;
496                     String modelName = ap.getKey();
497                     if (modelName.equals("TrafficComposition"))
498                     {
499                         this.carProbability = pdp.getValue()[0];
500                     }
501                 }
502                 else if (ap instanceof CompoundProperty)
503                 {
504                     CompoundProperty cp = (CompoundProperty) ap;
505                     if (ap.getKey().equals("OutputGraphs"))
506                     {
507                         continue; // Output settings are handled elsewhere
508                     }
509                     if (ap.getKey().contains("IDM"))
510                     {
511                         Acceleration a = IDMPropertySet.getA(cp);
512                         Acceleration b = IDMPropertySet.getB(cp);
513                         Length s0 = IDMPropertySet.getS0(cp);
514                         Duration tSafe = IDMPropertySet.getTSafe(cp);
515                         GTUFollowingModelOld gtuFollowingModel = null;
516                         if (carFollowingModelName.equals("IDM"))
517                         {
518                             gtuFollowingModel = new IDMOld(a, b, s0, tSafe, 1.0);
519                         }
520                         else if (carFollowingModelName.equals("IDM+"))
521                         {
522                             gtuFollowingModel = new IDMPlusOld(a, b, s0, tSafe, 1.0);
523                         }
524                         else
525                         {
526                             throw new Error("Unknown gtu following model: " + carFollowingModelName);
527                         }
528                         if (ap.getKey().contains("Car"))
529                         {
530                             this.carFollowingModelCars = gtuFollowingModel;
531                         }
532                         else if (ap.getKey().contains("Truck"))
533                         {
534                         }
535                         else
536                         {
537                             throw new Error("Cannot determine gtu type for " + ap.getKey());
538                         }
539                         /*
540                          * System.out.println("Created " + carFollowingModelName + " for " + p.getKey());
541                          * System.out.println("a: " + a); System.out.println("b: " + b); System.out.println("s0: " + s0);
542                          * System.out.println("tSafe: " + tSafe);
543                          */
544                     }
545                 }
546             }
547 
548             // 1500 [veh / hour] == 2.4s headway
549             this.headway = new Duration(3600.0 / 1500.0, SECOND);
550             // Schedule creation of the first car (it will re-schedule itself one headway later, etc.).
551             this.simulator.scheduleEventAbs(new Time(0.0, SECOND), this, this, "generateCar", null);
552             // Create a block at t = 5 minutes
553             this.simulator.scheduleEventAbs(new Time(300, SECOND), this, this, "createBlock", null);
554             // Remove the block at t = 7 minutes
555             this.simulator.scheduleEventAbs(new Time(420, SECOND), this, this, "removeBlock", null);
556             // Schedule regular updates of the graphs
557             for (int t = 1; t <= 1800; t++)
558             {
559                 this.simulator.scheduleEventAbs(new Time(t - 0.001, SECOND), this, this, "drawGraphs", null);
560             }
561         }
562         catch (SimRuntimeException | NamingException | NetworkException | OTSGeometryException | PropertyException exception)
563         {
564             exception.printStackTrace();
565         }
566     }
567 
568     /**
569      * Notify the contour plots that the underlying data has changed.
570      */
571     protected final void drawGraphs()
572     {
573         for (LaneBasedGTUSampler plot : this.plots)
574         {
575             plot.reGraph();
576         }
577     }
578 
579     /**
580      * Set up the block.
581      */
582     protected final void createBlock()
583     {
584         Length initialPosition = new Length(4000, METER);
585         Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
586         try
587         {
588             initialPositions.add(new DirectedLanePosition(this.lane, initialPosition, GTUDirectionality.DIR_PLUS));
589             BehavioralCharacteristics behavioralCharacteristics = DefaultsFactory.getDefaultBehavioralCharacteristics();
590 
591             this.block =
592                     new LaneBasedIndividualGTU("999999", this.gtuType, new Length(4, METER), new Length(1.8, METER), new Speed(
593                             0.0, KM_PER_HOUR), this.simulator, this.network);
594             LaneBasedStrategicalPlanner strategicalPlanner =
595                     new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics, new GTUFollowingTacticalPlannerNoPerceive(
596                             this.carFollowingModelCars, this.block), this.block);
597             this.block.initWithAnimation(strategicalPlanner, initialPositions, new Speed(0.0, KM_PER_HOUR),
598                     DefaultCarAnimation.class, this.gtuColorer);
599         }
600         catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
601         {
602             exception.printStackTrace();
603         }
604     }
605 
606     /**
607      * Remove the block.
608      */
609     protected final void removeBlock()
610     {
611         this.block.destroy();
612         this.block = null;
613     }
614 
615     /**
616      * Generate cars at a fixed rate (implemented by re-scheduling this method).
617      * @throws ParameterException in case of a parameter problem.
618      */
619     protected final void generateCar() throws ParameterException
620     {
621         boolean generateTruck = this.randomGenerator.nextDouble() > this.carProbability;
622         Length initialPosition = new Length(0, METER);
623         Speed initialSpeed = new Speed(100, KM_PER_HOUR);
624         Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
625         try
626         {
627             initialPositions.add(new DirectedLanePosition(this.lane, initialPosition, GTUDirectionality.DIR_PLUS));
628             Length vehicleLength = new Length(generateTruck ? 15 : 4, METER);
629             GTUFollowingModelOld gtuFollowingModel;
630             if (generateTruck)
631             {
632                 Acceleration a = new Acceleration(0.5, AccelerationUnit.METER_PER_SECOND_2); // max acceleration
633                 Acceleration b = new Acceleration(1.25, AccelerationUnit.METER_PER_SECOND_2); // max xomfortable deceleration
634                 Length s0 = new Length(4, LengthUnit.METER); // headway distance
635                 Duration tSafe = new Duration(2.0, TimeUnit.SECOND); // time headway
636                 gtuFollowingModel = new IDMPlusOld(a, b, s0, tSafe, 1.0);
637             }
638             else
639             {
640                 Acceleration a = new Acceleration(2.0, AccelerationUnit.METER_PER_SECOND_2); // max acceleration
641                 Acceleration b = new Acceleration(3, AccelerationUnit.METER_PER_SECOND_2); // max xomfortable deceleration
642                 Length s0 = new Length(2.0, LengthUnit.METER); // headway distance
643                 Duration tSafe = new Duration(1.0, TimeUnit.SECOND); // time headway
644                 gtuFollowingModel = new IDMPlusOld(a, b, s0, tSafe, 1.0);
645             }
646             BehavioralCharacteristics behavioralCharacteristics = DefaultsFactory.getDefaultBehavioralCharacteristics();
647             LaneBasedPerceivingCar car =
648                     new LaneBasedPerceivingCar("" + (++this.carsCreated), this.gtuType, vehicleLength, new Length(1.8, METER),
649                             new Speed(200, KM_PER_HOUR), this.simulator, this.network);
650             LaneBasedStrategicalPlanner strategicalPlanner =
651                     new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics, new GTUFollowingTacticalPlannerNoPerceive(
652                             gtuFollowingModel, car), car);
653             car.initWithAnimation(strategicalPlanner, initialPositions, initialSpeed, DefaultCarAnimation.class,
654                     this.gtuColorer);
655             this.simulator.scheduleEventRel(this.headway, this, this, "generateCar", null);
656             car.setPerceptionInterval(new Duration(this.perceptionIntervalDist.draw(), TimeUnit.SECOND));
657             car.getStrategicalPlanner().getBehavioralCharacteristics()
658                     .setParameter(ParameterTypes.LOOKAHEAD, new Length(this.forwardHeadwayDist.draw(), LengthUnit.METER));
659             // .setForwardHeadwayDistance(new Length(this.forwardHeadwayDist.draw(), LengthUnit.METER));
660         }
661         catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
662         {
663             exception.printStackTrace();
664         }
665     }
666 
667     /** {@inheritDoc} */
668     @Override
669     public final SimulatorInterface<Time, Duration, OTSSimTimeDouble> getSimulator() throws RemoteException
670     {
671         return this.simulator;
672     }
673 
674     /**
675      * @return contourPlots
676      */
677     public final List<LaneBasedGTUSampler> getPlots()
678     {
679         return this.plots;
680     }
681 
682     /**
683      * @return minimumDistance
684      */
685     public final Length getMinimumDistance()
686     {
687         return this.minimumDistance;
688     }
689 
690     /**
691      * @return maximumDistance
692      */
693     public final Length getMaximumDistance()
694     {
695         return this.maximumDistance;
696     }
697 
698     /**
699      * @return lane.
700      */
701     public Lane getLane()
702     {
703         return this.lane;
704     }
705 
706     /**
707      * Perceiving car.
708      */
709     class LaneBasedPerceivingCar extends LaneBasedIndividualGTU
710     {
711         /** */
712         private static final long serialVersionUID = 1L;
713 
714         /** */
715         private Duration perceptionInterval = new Duration(0.5, TimeUnit.SECOND);
716 
717         /**
718          * @param id ID; the id of the GTU
719          * @param gtuType GTUType; the type of GTU, e.g. TruckType, CarType, BusType
720          * @param length Length; the maximum length of the GTU (parallel with driving direction)
721          * @param width Length; the maximum width of the GTU (perpendicular to driving direction)
722          * @param maximumSpeed Speed;the maximum speed of the GTU (in the driving direction)
723          * @param simulator OTSDEVSSimulatorInterface; the simulator
724          * @param network the network that the GTU is initially registered in
725          * @throws NamingException if an error occurs when adding the animation handler
726          * @throws NetworkException when the GTU cannot be placed on the given lane
727          * @throws SimRuntimeException when the move method cannot be scheduled
728          * @throws GTUException when a parameter is invalid
729          * @throws OTSGeometryException when the initial path is wrong
730          * @throws ParameterException in case of a parameter problem.
731          */
732         LaneBasedPerceivingCar(final String id, final GTUType gtuType, final Length length, final Length width,
733                 final Speed maximumSpeed, final OTSDEVSSimulatorInterface simulator, final OTSNetwork network)
734                 throws NamingException, NetworkException, SimRuntimeException, GTUException, OTSGeometryException,
735                 ParameterException
736         {
737             super(id, gtuType, length, width, maximumSpeed, simulator, network);
738             perceive();
739         }
740 
741         /**
742          * @param perceptionInterval the interval for perceiving.
743          */
744         public void setPerceptionInterval(final Duration perceptionInterval)
745         {
746             this.perceptionInterval = perceptionInterval;
747         }
748 
749         /**
750          * Perceive and reschedule.
751          * @throws SimRuntimeException RTE
752          * @throws GTUException GTUE
753          * @throws NetworkException NE
754          * @throws ParameterException in case of a parameter problem.
755          */
756         public void perceive() throws SimRuntimeException, GTUException, NetworkException, ParameterException
757         {
758             getTacticalPlanner().getPerception().perceive();
759             getSimulator().scheduleEventRel(this.perceptionInterval, this, this, "perceive", null);
760         }
761     }
762 
763     /**
764      * Tactical planner without perception update.
765      */
766     class GTUFollowingTacticalPlannerNoPerceive extends AbstractLaneBasedTacticalPlanner
767     {
768         /** */
769         private static final long serialVersionUID = 20151125L;
770 
771         /**
772          * Instantiated a tactical planner with just GTU following behavior and no lane changes.
773          * @param carFollowingModel Car-following model.
774          * @param gtu GTU
775          */
776         GTUFollowingTacticalPlannerNoPerceive(final GTUFollowingModelOld carFollowingModel, final LaneBasedGTU gtu)
777         {
778             super(carFollowingModel, gtu);
779         }
780 
781         /** {@inheritDoc} */
782         @Override
783         public OperationalPlan generateOperationalPlan(final Time startTime, final DirectedPoint locationAtStartTime)
784                 throws OperationalPlanException, NetworkException, GTUException, ParameterException
785         {
786             // ask Perception for the local situation
787 
788             // if the GTU's maximum speed is zero (block), generate a stand still plan
789             if (getGtu().getMaximumSpeed().si < OperationalPlan.DRIFTING_SPEED_SI)
790             {
791                 // time equal to fastest reaction time of GTU
792                 return new OperationalPlan(getGtu(), locationAtStartTime, startTime, new Duration(
793                         perceptionIntervalDist.draw(), TimeUnit.SECOND));
794             }
795 
796             // get some models to help us make a plan
797             // GTUFollowingModelOld gtuFollowingModel =
798             // laneBasedGTU.getStrategicalPlanner().getBehavioralCharacteristics().getGTUFollowingModel();
799 
800             // get the lane plan
801             LanePathInfo lanePathInfo =
802                     buildLanePathInfo(getGtu(), getGtu().getBehavioralCharacteristics().getParameter(ParameterTypes.LOOKAHEAD));
803             Length maxDistance = lanePathInfo.getPath().getLength();
804 
805             // look at the conditions for headway
806             Headway headway = getPerception().getPerceptionCategory(DefaultSimplePerception.class).getForwardHeadwayGTU();
807             AccelerationStep accelerationStep = null;
808             if (headway.getDistance().le(maxDistance))
809             {
810                 accelerationStep =
811                         ((GTUFollowingModelOld) this.getCarFollowingModel()).computeAccelerationStepWithNoLeader(getGtu(),
812                                 maxDistance, getPerception().getPerceptionCategory(DefaultSimplePerception.class).getSpeedLimit());
813             }
814             else
815             {
816                 // TODO do not use the speed of the other GTU, but the PERCEIVED speed
817                 accelerationStep =
818                         ((GTUFollowingModelOld) this.getCarFollowingModel()).computeAccelerationStep(getGtu(),
819                                 headway.getSpeed(), headway.getDistance(), maxDistance,
820                                 getPerception().getPerceptionCategory(DefaultSimplePerception.class).getSpeedLimit());
821             }
822 
823             // see if we have to continue standing still. In that case, generate a stand still plan
824             if (accelerationStep.getAcceleration().si < 1E-6 && getGtu().getSpeed().si < OperationalPlan.DRIFTING_SPEED_SI)
825             {
826                 return new OperationalPlan(getGtu(), locationAtStartTime, startTime, accelerationStep.getDuration());
827             }
828 
829             List<Segment> operationalPlanSegmentList = new ArrayList<>();
830             if (accelerationStep.getAcceleration().si == 0.0)
831             {
832                 Segment segment = new OperationalPlan.SpeedSegment(accelerationStep.getDuration());
833                 operationalPlanSegmentList.add(segment);
834             }
835             else
836             {
837                 Segment segment =
838                         new OperationalPlan.AccelerationSegment(accelerationStep.getDuration(),
839                                 accelerationStep.getAcceleration());
840                 operationalPlanSegmentList.add(segment);
841             }
842             OperationalPlan op =
843                     new OperationalPlan(getGtu(), lanePathInfo.getPath(), startTime, getGtu().getSpeed(),
844                             operationalPlanSegmentList);
845             return op;
846         }
847     }
848 }