View Javadoc
1   package org.opentrafficsim.demo.carFollowing;
2   
3   import java.awt.Container;
4   import java.awt.Frame;
5   import java.awt.geom.Rectangle2D;
6   import java.io.IOException;
7   import java.net.URL;
8   import java.rmi.RemoteException;
9   import java.util.ArrayList;
10  import java.util.HashSet;
11  import java.util.LinkedHashSet;
12  import java.util.List;
13  import java.util.Random;
14  import java.util.Set;
15  
16  import javax.naming.NamingException;
17  import javax.swing.JComponent;
18  import javax.swing.JPanel;
19  import javax.swing.JScrollPane;
20  import javax.swing.SwingUtilities;
21  
22  import nl.tudelft.simulation.dsol.SimRuntimeException;
23  import nl.tudelft.simulation.dsol.gui.swing.HTMLPanel;
24  import nl.tudelft.simulation.dsol.gui.swing.TablePanel;
25  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
26  import nl.tudelft.simulation.jstats.distributions.DistContinuous;
27  import nl.tudelft.simulation.jstats.distributions.DistTriangular;
28  import nl.tudelft.simulation.jstats.streams.MersenneTwister;
29  import nl.tudelft.simulation.language.d3.DirectedPoint;
30  
31  import org.djunits.unit.AccelerationUnit;
32  import org.djunits.unit.LengthUnit;
33  import org.djunits.unit.TimeUnit;
34  import org.djunits.unit.UNITS;
35  import org.djunits.value.vdouble.scalar.Acceleration;
36  import org.djunits.value.vdouble.scalar.Duration;
37  import org.djunits.value.vdouble.scalar.Length;
38  import org.djunits.value.vdouble.scalar.Speed;
39  import org.djunits.value.vdouble.scalar.Time;
40  import org.opentrafficsim.base.modelproperties.BooleanProperty;
41  import org.opentrafficsim.base.modelproperties.CompoundProperty;
42  import org.opentrafficsim.base.modelproperties.ProbabilityDistributionProperty;
43  import org.opentrafficsim.base.modelproperties.Property;
44  import org.opentrafficsim.base.modelproperties.PropertyException;
45  import org.opentrafficsim.base.modelproperties.SelectionProperty;
46  import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
47  import org.opentrafficsim.core.dsol.OTSModelInterface;
48  import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
49  import org.opentrafficsim.core.geometry.OTSGeometryException;
50  import org.opentrafficsim.core.geometry.OTSPoint3D;
51  import org.opentrafficsim.core.gtu.GTUDirectionality;
52  import org.opentrafficsim.core.gtu.GTUException;
53  import org.opentrafficsim.core.gtu.GTUType;
54  import org.opentrafficsim.core.gtu.animation.GTUColorer;
55  import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
56  import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterException;
57  import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypes;
58  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan;
59  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan.Segment;
60  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
61  import org.opentrafficsim.core.network.LongitudinalDirectionality;
62  import org.opentrafficsim.core.network.NetworkException;
63  import org.opentrafficsim.core.network.OTSNetwork;
64  import org.opentrafficsim.core.network.OTSNode;
65  import org.opentrafficsim.graphs.AccelerationContourPlot;
66  import org.opentrafficsim.graphs.ContourPlot;
67  import org.opentrafficsim.graphs.DensityContourPlot;
68  import org.opentrafficsim.graphs.FlowContourPlot;
69  import org.opentrafficsim.graphs.LaneBasedGTUSampler;
70  import org.opentrafficsim.graphs.SpeedContourPlot;
71  import org.opentrafficsim.graphs.TrajectoryPlot;
72  import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
73  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
74  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
75  import org.opentrafficsim.road.gtu.lane.perception.categories.DefaultSimplePerception;
76  import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
77  import org.opentrafficsim.road.gtu.lane.tactical.AbstractLaneBasedTacticalPlanner;
78  import org.opentrafficsim.road.gtu.lane.tactical.LanePathInfo;
79  import org.opentrafficsim.road.gtu.lane.tactical.following.AccelerationStep;
80  import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
81  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMOld;
82  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
83  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
84  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
85  import org.opentrafficsim.road.modelproperties.IDMPropertySet;
86  import org.opentrafficsim.road.network.factory.LaneFactory;
87  import org.opentrafficsim.road.network.lane.CrossSectionLink;
88  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
89  import org.opentrafficsim.road.network.lane.Lane;
90  import org.opentrafficsim.road.network.lane.LaneType;
91  import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
92  import org.opentrafficsim.road.network.lane.object.sensor.Sensor;
93  import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
94  import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
95  import org.opentrafficsim.simulationengine.OTSSimulationException;
96  import org.opentrafficsim.simulationengine.SimpleSimulatorInterface;
97  
98  /**
99   * Simplest contour plots demonstration.
100  * <p>
101  * Copyright (c) 2013-2016 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.add(new BooleanProperty("AccelerationPlot", "Acceleration", "Acceleration contour plot", true, false,
127                 3));
128         outputProperties.add(new BooleanProperty("TrajectoryPlot", "Trajectories", "Trajectory (time/distance) diagram", true,
129                 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>", new String[] { "IDM", "IDM+" }, 1, false, 1));
175                     localProperties.add(IDMPropertySet.makeIDMPropertySet("IDMCar", "Car", new Acceleration(1.0,
176                             METER_PER_SECOND_2), new Acceleration(1.5, METER_PER_SECOND_2), new Length(2.0, METER),
177                             new Duration(1.0, SECOND), 2));
178                     localProperties.add(IDMPropertySet.makeIDMPropertySet("IDMTruck", "Truck", new Acceleration(0.5,
179                             METER_PER_SECOND_2), new Acceleration(1.25, METER_PER_SECOND_2), new Length(2.0, METER),
180                             new Duration(1.0, SECOND), 3));
181                     straight.buildAnimator(new Time(0.0, SECOND), new Duration(0.0, SECOND), new Duration(3600.0, SECOND),
182                             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 Rectangle2D.Double makeAnimationRectangle()
196     {
197         return new Rectangle2D.Double(0, -100, 5000, 200);
198     }
199 
200     /** {@inheritDoc} */
201     @Override
202     protected final OTSModelInterface makeModel(final GTUColorer colorer)
203     {
204         this.model = new StraightPerceptionModel(this.savedUserModifiedProperties, colorer);
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 JPanel makeCharts(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         return 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 
340 /**
341  * Simulate a single lane road of 5 km length. Vehicles are generated at a constant rate of 1500 veh/hour. At time 300s a
342  * blockade is inserted at position 4 km; this blockade is removed at time 500s. The used car following algorithm is IDM+ <a
343  * href="http://opentrafficsim.org/downloads/MOTUS%20reference.pdf"><i>Integrated Lane Change Model with Relaxation and
344  * Synchronization</i>, by Wouter J. Schakel, Victor L. Knoop and Bart van Arem, 2012</a>. <br>
345  * Output is a set of block charts:
346  * <ul>
347  * <li>Traffic density</li>
348  * <li>Speed</li>
349  * <li>Flow</li>
350  * <li>Acceleration</li>
351  * </ul>
352  * All these graphs display simulation time along the horizontal axis and distance along the road along the vertical axis.
353  * <p>
354  * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
355  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
356  * <p>
357  * $LastChangedDate: 2016-01-05 06:14:49 +0100 (Tue, 05 Jan 2016) $, @version $Revision: 1685 $, by $Author: averbraeck $,
358  * initial version ug 1, 2014 <br>
359  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
360  */
361 class StraightPerceptionModel implements OTSModelInterface, UNITS
362 {
363     /** */
364     private static final long serialVersionUID = 20140815L;
365 
366     /** The simulator. */
367     private OTSDEVSSimulatorInterface simulator;
368 
369     /** The network. */
370     private OTSNetwork network = new OTSNetwork("network");
371 
372     /** The headway (inter-vehicle time). */
373     private Duration headway;
374 
375     /** Number of cars created. */
376     private int carsCreated = 0;
377 
378     /** Type of all GTUs. */
379     private GTUType gtuType = new GTUType("Car");
380 
381     /** The car following model, e.g. IDM Plus for cars. */
382     private GTUFollowingModelOld carFollowingModelCars;
383 
384     /** The probability that the next generated GTU is a passenger car. */
385     private double carProbability;
386 
387     /** The blocking car. */
388     private LaneBasedIndividualGTU block = null;
389 
390     /** Minimum distance. */
391     private Length minimumDistance = new Length(0, METER);
392 
393     /** Maximum distance. */
394     private Length maximumDistance = new Length(5000, METER);
395 
396     /** The Lane that contains the simulated Cars. */
397     private Lane lane;
398 
399     /** The contour plots. */
400     private List<LaneBasedGTUSampler> plots = new ArrayList<>();
401 
402     /** User settable properties. */
403     private List<Property<?>> properties = null;
404 
405     /** The random number generator used to decide what kind of GTU to generate. */
406     private Random randomGenerator = new Random(12345);
407 
408     /** The GTUColorer for the generated vehicles. */
409     private final GTUColorer gtuColorer;
410 
411     /**
412      * @param properties the user settable properties
413      * @param gtuColorer the default and initial GTUColorer, e.g. a DefaultSwitchableTUColorer.
414      */
415     StraightPerceptionModel(final List<Property<?>> properties, final GTUColorer gtuColorer)
416     {
417         this.properties = properties;
418         this.gtuColorer = gtuColorer;
419     }
420 
421     /** The sequence of Lanes that all vehicles will follow. */
422     private List<Lane> path = new ArrayList<>();
423 
424     /** The speed limit on all Lanes. */
425     private Speed speedLimit = new Speed(100, KM_PER_HOUR);
426 
427     /** The perception interval distribution. */
428     @SuppressWarnings("visibilitymodifier")
429     DistContinuous perceptionIntervalDist = new DistTriangular(new MersenneTwister(2), 0.25, 1, 2);
430 
431     /** The forward headway distribution. */
432     @SuppressWarnings("visibilitymodifier")
433     DistContinuous forwardHeadwayDist = new DistTriangular(new MersenneTwister(20), 20, 50, 100);
434 
435     /**
436      * @return List&lt;Lane&gt;; the set of lanes for the specified index
437      */
438     public List<Lane> getPath()
439     {
440         return new ArrayList<>(this.path);
441     }
442 
443     /** {@inheritDoc} */
444     @Override
445     public final void constructModel(final SimulatorInterface<Time, Duration, OTSSimTimeDouble> theSimulator)
446             throws SimRuntimeException, RemoteException
447     {
448         this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
449         try
450         {
451             OTSNode from = new OTSNode(this.network, "From", new OTSPoint3D(getMinimumDistance().getSI(), 0, 0));
452             OTSNode to = new OTSNode(this.network, "To", new OTSPoint3D(getMaximumDistance().getSI(), 0, 0));
453             OTSNode end = new OTSNode(this.network, "End", new OTSPoint3D(getMaximumDistance().getSI() + 50.0, 0, 0));
454             Set<GTUType> compatibility = new HashSet<>();
455             compatibility.add(this.gtuType);
456             LaneType laneType = new LaneType("CarLane", compatibility);
457             this.lane =
458                     LaneFactory.makeLane(this.network, "Lane", from, to, null, laneType, this.speedLimit, this.simulator,
459                             LongitudinalDirectionality.DIR_PLUS);
460             this.path.add(this.lane);
461             CrossSectionLink endLink =
462                     LaneFactory.makeLink(this.network, "endLink", to, end, null, LongitudinalDirectionality.DIR_PLUS);
463             // No overtaking, single lane
464             Lane sinkLane =
465                     new Lane(endLink, "sinkLane", this.lane.getLateralCenterPosition(1.0),
466                             this.lane.getLateralCenterPosition(1.0), this.lane.getWidth(1.0), this.lane.getWidth(1.0),
467                             laneType, LongitudinalDirectionality.DIR_PLUS, this.speedLimit, new OvertakingConditions.None());
468             Sensor sensor = new SinkSensor(sinkLane, new Length(10.0, METER), this.simulator);
469             sinkLane.addSensor(sensor, GTUType.ALL);
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     /**
677      * @return contourPlots
678      */
679     public final List<LaneBasedGTUSampler> getPlots()
680     {
681         return this.plots;
682     }
683 
684     /**
685      * @return minimumDistance
686      */
687     public final Length getMinimumDistance()
688     {
689         return this.minimumDistance;
690     }
691 
692     /**
693      * @return maximumDistance
694      */
695     public final Length getMaximumDistance()
696     {
697         return this.maximumDistance;
698     }
699 
700     /**
701      * @return lane.
702      */
703     public Lane getLane()
704     {
705         return this.lane;
706     }
707 
708     /**
709      * Perceiving car.
710      */
711     class LaneBasedPerceivingCar extends LaneBasedIndividualGTU
712     {
713         /** */
714         private static final long serialVersionUID = 1L;
715 
716         /** */
717         private Duration perceptionInterval = new Duration(0.5, TimeUnit.SECOND);
718 
719         /**
720          * @param id ID; the id of the GTU
721          * @param gtuType GTUType; the type of GTU, e.g. TruckType, CarType, BusType
722          * @param length Length; the maximum length of the GTU (parallel with driving direction)
723          * @param width Length; the maximum width of the GTU (perpendicular to driving direction)
724          * @param maximumSpeed Speed;the maximum speed of the GTU (in the driving direction)
725          * @param simulator OTSDEVSSimulatorInterface; the simulator
726          * @param network the network that the GTU is initially registered in
727          * @throws NamingException if an error occurs when adding the animation handler
728          * @throws NetworkException when the GTU cannot be placed on the given lane
729          * @throws SimRuntimeException when the move method cannot be scheduled
730          * @throws GTUException when a parameter is invalid
731          * @throws OTSGeometryException when the initial path is wrong
732          * @throws ParameterException in case of a parameter problem.
733          */
734         LaneBasedPerceivingCar(final String id, final GTUType gtuType, final Length length, final Length width,
735                 final Speed maximumSpeed, final OTSDEVSSimulatorInterface simulator, final OTSNetwork network)
736                 throws NamingException, NetworkException, SimRuntimeException, GTUException, OTSGeometryException,
737                 ParameterException
738         {
739             super(id, gtuType, length, width, maximumSpeed, simulator, network);
740             perceive();
741         }
742 
743         /**
744          * @param perceptionInterval the interval for perceiving.
745          */
746         public void setPerceptionInterval(final Duration perceptionInterval)
747         {
748             this.perceptionInterval = perceptionInterval;
749         }
750 
751         /**
752          * Perceive and reschedule.
753          * @throws SimRuntimeException RTE
754          * @throws GTUException GTUE
755          * @throws NetworkException NE
756          * @throws ParameterException in case of a parameter problem.
757          */
758         public void perceive() throws SimRuntimeException, GTUException, NetworkException, ParameterException
759         {
760             getTacticalPlanner().getPerception().perceive();
761             getSimulator().scheduleEventRel(this.perceptionInterval, this, this, "perceive", null);
762         }
763     }
764 
765     /**
766      * Tactical planner without perception update.
767      */
768     class GTUFollowingTacticalPlannerNoPerceive extends AbstractLaneBasedTacticalPlanner
769     {
770         /** */
771         private static final long serialVersionUID = 20151125L;
772 
773         /**
774          * Instantiated a tactical planner with just GTU following behavior and no lane changes.
775          * @param carFollowingModel Car-following model.
776          * @param gtu GTU
777          */
778         GTUFollowingTacticalPlannerNoPerceive(final GTUFollowingModelOld carFollowingModel, final LaneBasedGTU gtu)
779         {
780             super(carFollowingModel, gtu);
781         }
782 
783         /** {@inheritDoc} */
784         @Override
785         public OperationalPlan generateOperationalPlan(final Time startTime, final DirectedPoint locationAtStartTime)
786                 throws OperationalPlanException, NetworkException, GTUException, ParameterException
787         {
788             // ask Perception for the local situation
789 
790             // if the GTU's maximum speed is zero (block), generate a stand still plan
791             if (getGtu().getMaximumSpeed().si < OperationalPlan.DRIFTING_SPEED_SI)
792             {
793                 // time equal to fastest reaction time of GTU
794                 return new OperationalPlan(getGtu(), locationAtStartTime, startTime, new Duration(
795                         perceptionIntervalDist.draw(), TimeUnit.SECOND));
796             }
797 
798             // get some models to help us make a plan
799             // GTUFollowingModelOld gtuFollowingModel =
800             // laneBasedGTU.getStrategicalPlanner().getBehavioralCharacteristics().getGTUFollowingModel();
801 
802             // get the lane plan
803             LanePathInfo lanePathInfo =
804                     buildLanePathInfo(getGtu(), getGtu().getBehavioralCharacteristics().getParameter(ParameterTypes.LOOKAHEAD));
805             Length maxDistance = lanePathInfo.getPath().getLength();
806 
807             // look at the conditions for headway
808             Headway headway = getPerception().getPerceptionCategory(DefaultSimplePerception.class).getForwardHeadway();
809             AccelerationStep accelerationStep = null;
810             if (headway.getDistance().le(maxDistance))
811             {
812                 accelerationStep =
813                         ((GTUFollowingModelOld) this.getCarFollowingModel()).computeAccelerationStepWithNoLeader(getGtu(),
814                                 maxDistance, getPerception().getPerceptionCategory(DefaultSimplePerception.class).getSpeedLimit());
815             }
816             else
817             {
818                 // TODO do not use the speed of the other GTU, but the PERCEIVED speed
819                 accelerationStep =
820                         ((GTUFollowingModelOld) this.getCarFollowingModel()).computeAccelerationStep(getGtu(),
821                                 headway.getSpeed(), headway.getDistance(), maxDistance,
822                                 getPerception().getPerceptionCategory(DefaultSimplePerception.class).getSpeedLimit());
823             }
824 
825             // see if we have to continue standing still. In that case, generate a stand still plan
826             if (accelerationStep.getAcceleration().si < 1E-6 && getGtu().getSpeed().si < OperationalPlan.DRIFTING_SPEED_SI)
827             {
828                 return new OperationalPlan(getGtu(), locationAtStartTime, startTime, accelerationStep.getDuration());
829             }
830 
831             List<Segment> operationalPlanSegmentList = new ArrayList<>();
832             if (accelerationStep.getAcceleration().si == 0.0)
833             {
834                 Segment segment = new OperationalPlan.SpeedSegment(accelerationStep.getDuration());
835                 operationalPlanSegmentList.add(segment);
836             }
837             else
838             {
839                 Segment segment =
840                         new OperationalPlan.AccelerationSegment(accelerationStep.getDuration(),
841                                 accelerationStep.getAcceleration());
842                 operationalPlanSegmentList.add(segment);
843             }
844             OperationalPlan op =
845                     new OperationalPlan(getGtu(), lanePathInfo.getPath(), startTime, getGtu().getSpeed(),
846                             operationalPlanSegmentList);
847             return op;
848         }
849     }
850 }