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