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