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.Iterator;
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 nl.tudelft.simulation.dsol.SimRuntimeException;
24  import nl.tudelft.simulation.dsol.animation.D2.Renderable2D;
25  import nl.tudelft.simulation.dsol.gui.swing.HTMLPanel;
26  import nl.tudelft.simulation.dsol.gui.swing.TablePanel;
27  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
28  import nl.tudelft.simulation.jstats.distributions.DistContinuous;
29  import nl.tudelft.simulation.jstats.distributions.DistTriangular;
30  import nl.tudelft.simulation.jstats.streams.MersenneTwister;
31  import nl.tudelft.simulation.language.d3.DirectedPoint;
32  
33  import org.djunits.unit.AccelerationUnit;
34  import org.djunits.unit.LengthUnit;
35  import org.djunits.unit.TimeUnit;
36  import org.djunits.unit.UNITS;
37  import org.djunits.value.vdouble.scalar.Acceleration;
38  import org.djunits.value.vdouble.scalar.DoubleScalar;
39  import org.djunits.value.vdouble.scalar.Duration;
40  import org.djunits.value.vdouble.scalar.Length;
41  import org.djunits.value.vdouble.scalar.Speed;
42  import org.djunits.value.vdouble.scalar.Time;
43  import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
44  import org.opentrafficsim.core.dsol.OTSModelInterface;
45  import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
46  import org.opentrafficsim.core.geometry.OTSGeometryException;
47  import org.opentrafficsim.core.geometry.OTSPoint3D;
48  import org.opentrafficsim.core.gtu.GTUDirectionality;
49  import org.opentrafficsim.core.gtu.GTUException;
50  import org.opentrafficsim.core.gtu.GTUType;
51  import org.opentrafficsim.core.gtu.animation.GTUColorer;
52  import org.opentrafficsim.core.gtu.behavioralcharacteristics.BehavioralCharacteristics;
53  import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterException;
54  import org.opentrafficsim.core.gtu.behavioralcharacteristics.ParameterTypes;
55  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan;
56  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlan.Segment;
57  import org.opentrafficsim.core.gtu.plan.operational.OperationalPlanException;
58  import org.opentrafficsim.core.network.LongitudinalDirectionality;
59  import org.opentrafficsim.core.network.NetworkException;
60  import org.opentrafficsim.core.network.OTSNetwork;
61  import org.opentrafficsim.core.network.OTSNode;
62  import org.opentrafficsim.graphs.AccelerationContourPlot;
63  import org.opentrafficsim.graphs.ContourPlot;
64  import org.opentrafficsim.graphs.DensityContourPlot;
65  import org.opentrafficsim.graphs.FlowContourPlot;
66  import org.opentrafficsim.graphs.LaneBasedGTUSampler;
67  import org.opentrafficsim.graphs.SpeedContourPlot;
68  import org.opentrafficsim.graphs.TrajectoryPlot;
69  import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
70  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
71  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
72  import org.opentrafficsim.road.gtu.lane.perception.categories.DefaultAlexander;
73  import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;
74  import org.opentrafficsim.road.gtu.lane.tactical.AbstractLaneBasedTacticalPlanner;
75  import org.opentrafficsim.road.gtu.lane.tactical.LanePathInfo;
76  import org.opentrafficsim.road.gtu.lane.tactical.following.AccelerationStep;
77  import org.opentrafficsim.road.gtu.lane.tactical.following.GTUFollowingModelOld;
78  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMOld;
79  import org.opentrafficsim.road.gtu.lane.tactical.following.IDMPlusOld;
80  import org.opentrafficsim.road.gtu.strategical.LaneBasedStrategicalPlanner;
81  import org.opentrafficsim.road.gtu.strategical.route.LaneBasedStrategicalRoutePlanner;
82  import org.opentrafficsim.road.network.factory.LaneFactory;
83  import org.opentrafficsim.road.network.lane.CrossSectionLink;
84  import org.opentrafficsim.road.network.lane.DirectedLanePosition;
85  import org.opentrafficsim.road.network.lane.Lane;
86  import org.opentrafficsim.road.network.lane.LaneType;
87  import org.opentrafficsim.road.network.lane.Sensor;
88  import org.opentrafficsim.road.network.lane.SinkSensor;
89  import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
90  import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
91  import org.opentrafficsim.simulationengine.OTSSimulationException;
92  import org.opentrafficsim.simulationengine.properties.AbstractProperty;
93  import org.opentrafficsim.simulationengine.properties.BooleanProperty;
94  import org.opentrafficsim.simulationengine.properties.CompoundProperty;
95  import org.opentrafficsim.simulationengine.properties.IDMPropertySet;
96  import org.opentrafficsim.simulationengine.properties.ProbabilityDistributionProperty;
97  import org.opentrafficsim.simulationengine.properties.PropertyException;
98  import org.opentrafficsim.simulationengine.properties.SelectionProperty;
99  
100 /**
101  * Simplest contour plots demonstration.
102  * <p>
103  * Copyright (c) 2013-2016 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
104  * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
105  * <p>
106  * $LastChangedDate: 2016-01-05 06:14:49 +0100 (Tue, 05 Jan 2016) $, @version $Revision: 1685 $, by $Author: averbraeck $,
107  * initial version 12 nov. 2014 <br>
108  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
109  */
110 public class StraightPerception extends AbstractWrappableAnimation implements UNITS
111 {
112     /** */
113     private static final long serialVersionUID = 1L;
114 
115     /** The model. */
116     private StraightPerceptionModel model;
117 
118     /**
119      * Create a ContourPlots simulation.
120      * @throws PropertyException
121      */
122     public StraightPerception() throws PropertyException
123     {
124         ArrayList<AbstractProperty<?>> outputProperties = new ArrayList<>();
125         outputProperties.add(new BooleanProperty("DensityPlot", "Density", "Density contour plot", true, false, 0));
126         outputProperties.add(new BooleanProperty("FlowPlot", "Flow", "Flow contour plot", true, false, 1));
127         outputProperties.add(new BooleanProperty("SpeedPlot", "Speed", "Speed contour plot", true, false, 2));
128         outputProperties.add(new BooleanProperty("AccelerationPlot", "Acceleration", "Acceleration contour plot", true,
129             false, 3));
130         outputProperties.add(new BooleanProperty("TrajectoryPlot", "Trajectories", "Trajectory (time/distance) diagram",
131             true, false, 4));
132         this.properties.add(new CompoundProperty("OutputGraphs", "Output graphs", "Select the graphical output",
133             outputProperties, true, 1000));
134     }
135 
136     /** {@inheritDoc} */
137     @Override
138     public final void stopTimersThreads()
139     {
140         super.stopTimersThreads();
141         this.model = null;
142     }
143 
144     /**
145      * Main program.
146      * @param args String[]; the command line arguments (not used)
147      * @throws SimRuntimeException when simulation cannot be created with given parameters
148      */
149     public static void main(final String[] args) throws SimRuntimeException
150     {
151         SwingUtilities.invokeLater(new Runnable()
152         {
153             @Override
154             public void run()
155             {
156                 try
157                 {
158                     StraightPerception straight = new StraightPerception();
159                     ArrayList<AbstractProperty<?>> 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 Rectangle2D.Double makeAnimationRectangle()
197     {
198         return new Rectangle2D.Double(0, -100, 5000, 200);
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 JPanel makeCharts() throws OTSSimulationException, PropertyException
235     {
236 
237         // Make the tab with the plots
238         AbstractProperty<?> 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 (AbstractProperty<?> 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);
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         return 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 = new 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 ArrayList<LaneBasedGTUSampler> plots = new ArrayList<>();
402 
403     /** User settable properties. */
404     private ArrayList<AbstractProperty<?>> 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 ArrayList<AbstractProperty<?>> 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(
447         final SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> theSimulator)
448         throws SimRuntimeException, RemoteException
449     {
450         this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
451         OTSNode from = new OTSNode("From", new OTSPoint3D(getMinimumDistance().getSI(), 0, 0));
452         OTSNode to = new OTSNode("To", new OTSPoint3D(getMaximumDistance().getSI(), 0, 0));
453         OTSNode end = new OTSNode("End", new OTSPoint3D(getMaximumDistance().getSI() + 50.0, 0, 0));
454         try
455         {
456             Set<GTUType> compatibility = new HashSet<>();
457             compatibility.add(this.gtuType);
458             LaneType laneType = new LaneType("CarLane", compatibility);
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 = LaneFactory.makeLink("endLink", to, end, null, LongitudinalDirectionality.DIR_PLUS);
464             // No overtaking, single lane
465             Lane sinkLane =
466                 new Lane(endLink, "sinkLane", this.lane.getLateralCenterPosition(1.0), this.lane
467                     .getLateralCenterPosition(1.0), this.lane.getWidth(1.0), this.lane.getWidth(1.0), laneType,
468                     LongitudinalDirectionality.DIR_PLUS, this.speedLimit, new OvertakingConditions.None());
469             Sensor sensor = new SinkSensor(sinkLane, new Length(10.0, METER), this.simulator);
470             sinkLane.addSensor(sensor, GTUType.ALL);
471             String carFollowingModelName = null;
472             CompoundProperty propertyContainer = new CompoundProperty("", "", "", this.properties, false, 0);
473             AbstractProperty<?> cfmp = propertyContainer.findByKey("CarFollowingModel");
474             if (null == cfmp)
475             {
476                 throw new Error("Cannot find \"Car following model\" property");
477             }
478             if (cfmp instanceof SelectionProperty)
479             {
480                 carFollowingModelName = ((SelectionProperty) cfmp).getValue();
481             }
482             else
483             {
484                 throw new Error("\"Car following model\" property has wrong type");
485             }
486             Iterator<AbstractProperty<List<AbstractProperty<?>>>> iterator =
487                 new CompoundProperty("", "", "", this.properties, false, 0).iterator();
488             while (iterator.hasNext())
489             {
490                 AbstractProperty<?> ap = iterator.next();
491                 if (ap instanceof SelectionProperty)
492                 {
493                     SelectionProperty sp = (SelectionProperty) ap;
494                     if ("CarFollowingModel".equals(sp.getKey()))
495                     {
496                         carFollowingModelName = sp.getValue();
497                     }
498                 }
499                 else if (ap instanceof ProbabilityDistributionProperty)
500                 {
501                     ProbabilityDistributionProperty pdp = (ProbabilityDistributionProperty) ap;
502                     String modelName = ap.getKey();
503                     if (modelName.equals("TrafficComposition"))
504                     {
505                         this.carProbability = pdp.getValue()[0];
506                     }
507                 }
508                 else if (ap instanceof CompoundProperty)
509                 {
510                     CompoundProperty cp = (CompoundProperty) ap;
511                     if (ap.getKey().equals("OutputGraphs"))
512                     {
513                         continue; // Output settings are handled elsewhere
514                     }
515                     if (ap.getKey().contains("IDM"))
516                     {
517                         Acceleration a = IDMPropertySet.getA(cp);
518                         Acceleration b = IDMPropertySet.getB(cp);
519                         Length s0 = IDMPropertySet.getS0(cp);
520                         Duration tSafe = IDMPropertySet.getTSafe(cp);
521                         GTUFollowingModelOld gtuFollowingModel = null;
522                         if (carFollowingModelName.equals("IDM"))
523                         {
524                             gtuFollowingModel = new IDMOld(a, b, s0, tSafe, 1.0);
525                         }
526                         else if (carFollowingModelName.equals("IDM+"))
527                         {
528                             gtuFollowingModel = new IDMPlusOld(a, b, s0, tSafe, 1.0);
529                         }
530                         else
531                         {
532                             throw new Error("Unknown gtu following model: " + carFollowingModelName);
533                         }
534                         if (ap.getKey().contains("Car"))
535                         {
536                             this.carFollowingModelCars = gtuFollowingModel;
537                         }
538                         else if (ap.getKey().contains("Truck"))
539                         {
540                         }
541                         else
542                         {
543                             throw new Error("Cannot determine gtu type for " + ap.getKey());
544                         }
545                         /*
546                          * System.out.println("Created " + carFollowingModelName + " for " + p.getKey());
547                          * System.out.println("a: " + a); System.out.println("b: " + b); System.out.println("s0: " + s0);
548                          * System.out.println("tSafe: " + tSafe);
549                          */
550                     }
551                 }
552             }
553 
554             // 1500 [veh / hour] == 2.4s headway
555             this.headway = new Duration(3600.0 / 1500.0, SECOND);
556             // Schedule creation of the first car (it will re-schedule itself one headway later, etc.).
557             this.simulator.scheduleEventAbs(new DoubleScalar.Abs<>(0.0, SECOND), this, this, "generateCar", null);
558             // Create a block at t = 5 minutes
559             this.simulator.scheduleEventAbs(new DoubleScalar.Abs<>(300, SECOND), this, this, "createBlock", null);
560             // Remove the block at t = 7 minutes
561             this.simulator.scheduleEventAbs(new DoubleScalar.Abs<>(420, SECOND), this, this, "removeBlock", null);
562             // Schedule regular updates of the graphs
563             for (int t = 1; t <= 1800; t++)
564             {
565                 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<>(t - 0.001, SECOND), this, this, "drawGraphs",
566                     null);
567             }
568         }
569         catch (SimRuntimeException | NamingException | NetworkException | OTSGeometryException | PropertyException exception)
570         {
571             exception.printStackTrace();
572         }
573     }
574 
575     /**
576      * Notify the contour plots that the underlying data has changed.
577      */
578     protected final void drawGraphs()
579     {
580         for (LaneBasedGTUSampler plot : this.plots)
581         {
582             plot.reGraph();
583         }
584     }
585 
586     /**
587      * Set up the block.
588      */
589     protected final void createBlock()
590     {
591         Length initialPosition = new Length(4000, METER);
592         Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
593         try
594         {
595             initialPositions.add(new DirectedLanePosition(this.lane, initialPosition, GTUDirectionality.DIR_PLUS));
596             BehavioralCharacteristics behavioralCharacteristics = DefaultsFactory.getDefaultBehavioralCharacteristics();
597 
598             this.block =
599                 new LaneBasedIndividualGTU("999999", this.gtuType, new Length(4, METER), new Length(1.8, METER), new Speed(
600                     0.0, KM_PER_HOUR), this.simulator, DefaultCarAnimation.class, this.gtuColorer, this.network);
601             LaneBasedStrategicalPlanner strategicalPlanner =
602                 new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics, new GTUFollowingTacticalPlannerNoPerceive(
603                     this.carFollowingModelCars, this.block), this.block);
604             this.block.init(strategicalPlanner, initialPositions, new Speed(0.0, KM_PER_HOUR));
605         }
606         catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
607         {
608             exception.printStackTrace();
609         }
610     }
611 
612     /**
613      * Remove the block.
614      */
615     protected final void removeBlock()
616     {
617         this.block.destroy();
618         this.block = null;
619     }
620 
621     /**
622      * Generate cars at a fixed rate (implemented by re-scheduling this method).
623      * @throws ParameterException in case of a parameter problem.
624      */
625     protected final void generateCar() throws ParameterException
626     {
627         boolean generateTruck = this.randomGenerator.nextDouble() > this.carProbability;
628         Length initialPosition = new Length(0, METER);
629         Speed initialSpeed = new Speed(100, KM_PER_HOUR);
630         Set<DirectedLanePosition> initialPositions = new LinkedHashSet<>(1);
631         try
632         {
633             initialPositions.add(new DirectedLanePosition(this.lane, initialPosition, GTUDirectionality.DIR_PLUS));
634             Length vehicleLength = new Length(generateTruck ? 15 : 4, METER);
635             GTUFollowingModelOld gtuFollowingModel;
636             if (generateTruck)
637             {
638                 Acceleration a = new Acceleration(0.5, AccelerationUnit.METER_PER_SECOND_2); // max acceleration
639                 Acceleration b = new Acceleration(1.25, AccelerationUnit.METER_PER_SECOND_2); // max xomfortable deceleration
640                 Length s0 = new Length(4, LengthUnit.METER); // headway distance
641                 Duration tSafe = new Duration(2.0, TimeUnit.SECOND); // time headway
642                 gtuFollowingModel = new IDMPlusOld(a, b, s0, tSafe, 1.0);
643             }
644             else
645             {
646                 Acceleration a = new Acceleration(2.0, AccelerationUnit.METER_PER_SECOND_2); // max acceleration
647                 Acceleration b = new Acceleration(3, AccelerationUnit.METER_PER_SECOND_2); // max xomfortable deceleration
648                 Length s0 = new Length(2.0, LengthUnit.METER); // headway distance
649                 Duration tSafe = new Duration(1.0, TimeUnit.SECOND); // time headway
650                 gtuFollowingModel = new IDMPlusOld(a, b, s0, tSafe, 1.0);
651             }
652             BehavioralCharacteristics behavioralCharacteristics = DefaultsFactory.getDefaultBehavioralCharacteristics();
653             LaneBasedPerceivingCar car =
654                 new LaneBasedPerceivingCar("" + (++this.carsCreated), this.gtuType, vehicleLength, new Length(1.8, METER),
655                     new Speed(200, KM_PER_HOUR), this.simulator, DefaultCarAnimation.class, this.gtuColorer, this.network);
656             LaneBasedStrategicalPlanner strategicalPlanner =
657                 new LaneBasedStrategicalRoutePlanner(behavioralCharacteristics, new GTUFollowingTacticalPlannerNoPerceive(
658                     gtuFollowingModel, car), car);
659             car.init(strategicalPlanner, initialPositions, initialSpeed);
660             this.simulator.scheduleEventRel(this.headway, this, this, "generateCar", null);
661             car.setPerceptionInterval(new Duration(this.perceptionIntervalDist.draw(), TimeUnit.SECOND));
662             car.getStrategicalPlanner().getBehavioralCharacteristics().setParameter(ParameterTypes.LOOKAHEAD,
663                 new Length(this.forwardHeadwayDist.draw(), LengthUnit.METER));
664             // .setForwardHeadwayDistance(new Length(this.forwardHeadwayDist.draw(), LengthUnit.METER));
665         }
666         catch (SimRuntimeException | NamingException | NetworkException | GTUException | OTSGeometryException exception)
667         {
668             exception.printStackTrace();
669         }
670     }
671 
672     /** {@inheritDoc} */
673     @Override
674     public final SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> getSimulator()
675         throws RemoteException
676     {
677         return this.simulator;
678     }
679 
680     /**
681      * @return contourPlots
682      */
683     public final ArrayList<LaneBasedGTUSampler> getPlots()
684     {
685         return this.plots;
686     }
687 
688     /**
689      * @return minimumDistance
690      */
691     public final Length getMinimumDistance()
692     {
693         return this.minimumDistance;
694     }
695 
696     /**
697      * @return maximumDistance
698      */
699     public final Length getMaximumDistance()
700     {
701         return this.maximumDistance;
702     }
703 
704     /**
705      * @return lane.
706      */
707     public Lane getLane()
708     {
709         return this.lane;
710     }
711 
712     /**
713      * Perceiving car.
714      */
715     class LaneBasedPerceivingCar extends LaneBasedIndividualGTU
716     {
717         /** */
718         private static final long serialVersionUID = 1L;
719 
720         /** */
721         private Duration perceptionInterval = new Duration(0.5, TimeUnit.SECOND);
722 
723         /**
724          * @param id ID; the id of the GTU
725          * @param gtuType GTUType; the type of GTU, e.g. TruckType, CarType, BusType
726          * @param length Length; the maximum length of the GTU (parallel with driving direction)
727          * @param width Length; the maximum width of the GTU (perpendicular to driving direction)
728          * @param maximumSpeed Speed;the maximum speed of the GTU (in the driving direction)
729          * @param simulator OTSDEVSSimulatorInterface; the simulator
730          * @param network the network that the GTU is initially registered in
731          * @throws NamingException if an error occurs when adding the animation handler
732          * @throws NetworkException when the GTU cannot be placed on the given lane
733          * @throws SimRuntimeException when the move method cannot be scheduled
734          * @throws GTUException when a parameter is invalid
735          * @throws OTSGeometryException when the initial path is wrong
736          * @throws ParameterException in case of a parameter problem.
737          */
738         LaneBasedPerceivingCar(final String id, final GTUType gtuType, final Length length, final Length width,
739             final Speed maximumSpeed, final OTSDEVSSimulatorInterface simulator, final OTSNetwork network)
740             throws NamingException, NetworkException, SimRuntimeException, GTUException, OTSGeometryException,
741             ParameterException
742         {
743             super(id, gtuType, length, width, maximumSpeed, simulator, network);
744             perceive();
745         }
746 
747         /**
748          * Construct a new LaneBasedIndividualCar.
749          * @param id ID; the id of the GTU
750          * @param gtuType GTUTYpe; the type of GTU, e.g. TruckType, CarType, BusType
751          * @param length Length; the maximum length of the GTU (parallel with driving direction)
752          * @param width Length; the maximum width of the GTU (perpendicular to driving direction)
753          * @param maximumSpeed Speed;the maximum speed of the GTU (in the driving direction)
754          * @param simulator OTSDEVSSimulatorInterface; the simulator
755          * @param animationClass Class&lt;? extends Renderable2D&gt;; the class for animation or null if no animation
756          * @param gtuColorer GTUColorer; the GTUColorer that will be linked from the animation to determine the color (may be
757          *            null in which case a default will be used)
758          * @param network the network that the GTU is initially registered in
759          * @throws NamingException if an error occurs when adding the animation handler
760          * @throws NetworkException when the GTU cannot be placed on the given lane
761          * @throws SimRuntimeException when the move method cannot be scheduled
762          * @throws GTUException when a parameter is invalid
763          * @throws OTSGeometryException when the initial path is wrong
764          * @throws ParameterException in case of a parameter problem.
765          */
766         @SuppressWarnings("checkstyle:parameternumber")
767         LaneBasedPerceivingCar(final String id, final GTUType gtuType, final Length length, final Length width,
768             final Speed maximumSpeed, final OTSDEVSSimulatorInterface simulator,
769             final Class<? extends Renderable2D> animationClass, final GTUColorer gtuColorer, final OTSNetwork network)
770             throws NamingException, NetworkException, SimRuntimeException, GTUException, OTSGeometryException,
771             ParameterException
772         {
773             super(id, gtuType, length, width, maximumSpeed, simulator, animationClass, gtuColorer, network);
774             perceive();
775         }
776 
777         /**
778          * @param perceptionInterval the interval for perceiving.
779          */
780         public void setPerceptionInterval(final Duration perceptionInterval)
781         {
782             this.perceptionInterval = perceptionInterval;
783         }
784 
785         /**
786          * Perceive and reschedule.
787          * @throws SimRuntimeException RTE
788          * @throws GTUException GTUE
789          * @throws NetworkException NE
790          * @throws ParameterException in case of a parameter problem.
791          */
792         public void perceive() throws SimRuntimeException, GTUException, NetworkException, ParameterException
793         {
794             getTacticalPlanner().getPerception().perceive();
795             getSimulator().scheduleEventRel(this.perceptionInterval, this, this, "perceive", null);
796         }
797     }
798 
799     /**
800      * Tactical planner without perception update.
801      */
802     class GTUFollowingTacticalPlannerNoPerceive extends AbstractLaneBasedTacticalPlanner
803     {
804         /** */
805         private static final long serialVersionUID = 20151125L;
806 
807         /**
808          * Instantiated a tactical planner with just GTU following behavior and no lane changes.
809          * @param carFollowingModel Car-following model.
810          * @param gtu GTU
811          */
812         GTUFollowingTacticalPlannerNoPerceive(final GTUFollowingModelOld carFollowingModel, final LaneBasedGTU gtu)
813         {
814             super(carFollowingModel, gtu);
815         }
816 
817         /** {@inheritDoc} */
818         @Override
819         public OperationalPlan generateOperationalPlan(final Time startTime, final DirectedPoint locationAtStartTime)
820             throws OperationalPlanException, NetworkException, GTUException, ParameterException
821         {
822             // ask Perception for the local situation
823 
824             // if the GTU's maximum speed is zero (block), generate a stand still plan
825             if (getGtu().getMaximumSpeed().si < OperationalPlan.DRIFTING_SPEED_SI)
826             {
827                 // time equal to fastest reaction time of GTU
828                 return new OperationalPlan(getGtu(), locationAtStartTime, startTime, new Duration(perceptionIntervalDist
829                     .draw(), TimeUnit.SECOND));
830             }
831 
832             // get some models to help us make a plan
833             // GTUFollowingModelOld gtuFollowingModel =
834             // laneBasedGTU.getStrategicalPlanner().getBehavioralCharacteristics().getGTUFollowingModel();
835 
836             // get the lane plan
837             LanePathInfo lanePathInfo =
838                 buildLanePathInfo(getGtu(), getGtu().getBehavioralCharacteristics().getParameter(ParameterTypes.LOOKAHEAD));
839             Length maxDistance = lanePathInfo.getPath().getLength();
840 
841             // look at the conditions for headway
842             Headway headway = getPerception().getPerceptionCategory(DefaultAlexander.class).getForwardHeadway();
843             AccelerationStep accelerationStep = null;
844             if (headway.getDistance().le(maxDistance))
845             {
846                 accelerationStep =
847                     ((GTUFollowingModelOld) this.getCarFollowingModel()).computeAccelerationStepWithNoLeader(getGtu(),
848                         maxDistance, getPerception().getPerceptionCategory(DefaultAlexander.class).getSpeedLimit());
849             }
850             else
851             {
852                 // TODO do not use the speed of the other GTU, but the PERCEIVED speed
853                 accelerationStep =
854                     ((GTUFollowingModelOld) this.getCarFollowingModel()).computeAccelerationStep(getGtu(), headway
855                         .getSpeed(), headway.getDistance(), maxDistance, getPerception().getPerceptionCategory(
856                         DefaultAlexander.class).getSpeedLimit());
857             }
858 
859             // see if we have to continue standing still. In that case, generate a stand still plan
860             if (accelerationStep.getAcceleration().si < 1E-6 && getGtu().getSpeed().si < OperationalPlan.DRIFTING_SPEED_SI)
861             {
862                 return new OperationalPlan(getGtu(), locationAtStartTime, startTime, accelerationStep.getDuration());
863             }
864 
865             List<Segment> operationalPlanSegmentList = new ArrayList<>();
866             if (accelerationStep.getAcceleration().si == 0.0)
867             {
868                 Segment segment = new OperationalPlan.SpeedSegment(accelerationStep.getDuration());
869                 operationalPlanSegmentList.add(segment);
870             }
871             else
872             {
873                 Segment segment =
874                     new OperationalPlan.AccelerationSegment(accelerationStep.getDuration(), accelerationStep
875                         .getAcceleration());
876                 operationalPlanSegmentList.add(segment);
877             }
878             OperationalPlan op =
879                 new OperationalPlan(getGtu(), lanePathInfo.getPath(), startTime, getGtu().getSpeed(),
880                     operationalPlanSegmentList);
881             return op;
882         }
883     }
884 }