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