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