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.Collection;
11  import java.util.HashMap;
12  import java.util.Iterator;
13  import java.util.Map;
14  import java.util.Random;
15  
16  import javax.naming.NamingException;
17  import javax.swing.JScrollPane;
18  import javax.swing.SwingUtilities;
19  
20  import nl.tudelft.simulation.dsol.SimRuntimeException;
21  import nl.tudelft.simulation.dsol.gui.swing.HTMLPanel;
22  import nl.tudelft.simulation.dsol.gui.swing.TablePanel;
23  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
24  
25  import org.opentrafficsim.car.Car;
26  import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
27  import org.opentrafficsim.core.dsol.OTSModelInterface;
28  import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
29  import org.opentrafficsim.core.gtu.GTUType;
30  import org.opentrafficsim.core.gtu.following.GTUFollowingModel;
31  import org.opentrafficsim.core.gtu.following.GTUFollowingModel.GTUFollowingModelResult;
32  import org.opentrafficsim.core.gtu.following.IDM;
33  import org.opentrafficsim.core.gtu.following.IDMPlus;
34  import org.opentrafficsim.core.network.NetworkException;
35  import org.opentrafficsim.core.network.factory.LaneFactory;
36  import org.opentrafficsim.core.network.factory.Node;
37  import org.opentrafficsim.core.network.lane.Lane;
38  import org.opentrafficsim.core.network.lane.LaneType;
39  import org.opentrafficsim.core.unit.AccelerationUnit;
40  import org.opentrafficsim.core.unit.LengthUnit;
41  import org.opentrafficsim.core.unit.SpeedUnit;
42  import org.opentrafficsim.core.unit.TimeUnit;
43  import org.opentrafficsim.core.value.vdouble.scalar.DoubleScalar;
44  import org.opentrafficsim.graphs.AccelerationContourPlot;
45  import org.opentrafficsim.graphs.ContourPlot;
46  import org.opentrafficsim.graphs.DensityContourPlot;
47  import org.opentrafficsim.graphs.FlowContourPlot;
48  import org.opentrafficsim.graphs.LaneBasedGTUSampler;
49  import org.opentrafficsim.graphs.SpeedContourPlot;
50  import org.opentrafficsim.graphs.TrajectoryPlot;
51  import org.opentrafficsim.simulationengine.AbstractProperty;
52  import org.opentrafficsim.simulationengine.BooleanProperty;
53  import org.opentrafficsim.simulationengine.CompoundProperty;
54  import org.opentrafficsim.simulationengine.ControlPanel;
55  import org.opentrafficsim.simulationengine.IDMPropertySet;
56  import org.opentrafficsim.simulationengine.ProbabilityDistributionProperty;
57  import org.opentrafficsim.simulationengine.PropertyException;
58  import org.opentrafficsim.simulationengine.SelectionProperty;
59  import org.opentrafficsim.simulationengine.SimpleSimulator;
60  import org.opentrafficsim.simulationengine.SimulatorFrame;
61  import org.opentrafficsim.simulationengine.WrappableSimulation;
62  
63  import com.vividsolutions.jts.geom.Coordinate;
64  
65  /**
66   * Simplest contour plots demonstration.
67   * <p>
68   * Copyright (c) 2013-2014 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
69   * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
70   * <p>
71   * @version 12 nov. 2014 <br>
72   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
73   */
74  public class Straight implements WrappableSimulation
75  {
76      /** The properties exhibited by this simulation. */
77      private ArrayList<AbstractProperty<?>> properties = new ArrayList<AbstractProperty<?>>();
78  
79      /** Create a ContourPlots simulation. */
80      public Straight()
81      {
82          ArrayList<AbstractProperty<?>> outputProperties = new ArrayList<AbstractProperty<?>>();
83          outputProperties.add(new BooleanProperty("Density", "Density contour plot", true, false, 0));
84          outputProperties.add(new BooleanProperty("Flow", "Flow contour plot", true, false, 1));
85          outputProperties.add(new BooleanProperty("Speed", "Speed contour plot", true, false, 2));
86          outputProperties.add(new BooleanProperty("Acceleration", "Acceleration contour plot", true, false, 3));
87          outputProperties.add(new BooleanProperty("Trajectories", "Trajectory (time/distance) diagram", true, false, 4));
88          this.properties.add(new CompoundProperty("Output", "Select the graphical output", outputProperties, true, 1000));
89      }
90  
91      /**
92       * Main program.
93       * @param args String[]; the command line arguments (not used)
94       * @throws RemoteException on communications failure
95       * @throws SimRuntimeException when simulation cannot be created with given parameters
96       */
97      public static void main(final String[] args) throws RemoteException, SimRuntimeException
98      {
99          SwingUtilities.invokeLater(new Runnable()
100         {
101             @Override
102             public void run()
103             {
104                 try
105                 {
106                     Straight straight = new Straight();
107                     ArrayList<AbstractProperty<?>> localProperties = straight.getProperties();
108                     try
109                     {
110                         localProperties.add(new ProbabilityDistributionProperty("Traffic composition",
111                             "<html>Mix of passenger cars and trucks</html>", new String[] {"passenger car", "truck"},
112                             new Double[] {0.8, 0.2}, false, 10));
113                     }
114                     catch (PropertyException exception)
115                     {
116                         exception.printStackTrace();
117                     }
118                     localProperties.add(new SelectionProperty("Car following model",
119                         "<html>The car following model determines "
120                             + "the acceleration that a vehicle will make taking into account "
121                             + "nearby vehicles, infrastructural restrictions (e.g. speed limit, "
122                             + "curvature of the road) capabilities of the vehicle and personality "
123                             + "of the driver.</html>", new String[] {"IDM", "IDM+"}, 1, false, 1));
124                     localProperties.add(IDMPropertySet.makeIDMPropertySet("Car", new DoubleScalar.Abs<AccelerationUnit>(1.0,
125                         AccelerationUnit.METER_PER_SECOND_2), new DoubleScalar.Abs<AccelerationUnit>(1.5,
126                         AccelerationUnit.METER_PER_SECOND_2), new DoubleScalar.Rel<LengthUnit>(2.0, LengthUnit.METER),
127                         new DoubleScalar.Rel<TimeUnit>(1.0, TimeUnit.SECOND), 2));
128                     localProperties.add(IDMPropertySet.makeIDMPropertySet("Truck", new DoubleScalar.Abs<AccelerationUnit>(
129                         0.5, AccelerationUnit.METER_PER_SECOND_2), new DoubleScalar.Abs<AccelerationUnit>(1.25,
130                         AccelerationUnit.METER_PER_SECOND_2), new DoubleScalar.Rel<LengthUnit>(2.0, LengthUnit.METER),
131                         new DoubleScalar.Rel<TimeUnit>(1.0, TimeUnit.SECOND), 3));
132                     new SimulatorFrame("Contour Plots animation", straight.buildSimulator(localProperties).getPanel());
133                 }
134                 catch (RemoteException | SimRuntimeException exception)
135                 {
136                     exception.printStackTrace();
137                 }
138             }
139         });
140     }
141 
142     /**
143      * Create the simulation.
144      * @param userModifiedProperties the properties for the simulation.
145      * @return SimpleSimulator; the simulation
146      * @throws RemoteException on communications failure
147      * @throws SimRuntimeException when simulation cannot be created with given parameters
148      */
149     public final SimpleSimulator buildSimulator(final ArrayList<AbstractProperty<?>> userModifiedProperties)
150         throws SimRuntimeException, RemoteException
151     {
152         StraightModel model = new StraightModel(userModifiedProperties);
153         SimpleSimulator result =
154             new SimpleSimulator(new OTSSimTimeDouble(new DoubleScalar.Abs<TimeUnit>(0.0, TimeUnit.SECOND)),
155                 new DoubleScalar.Rel<TimeUnit>(0.0, TimeUnit.SECOND),
156                 new DoubleScalar.Rel<TimeUnit>(1800.0, TimeUnit.SECOND), model, new Rectangle2D.Double(0, -100, 5000, 200));
157         new ControlPanel(result);
158 
159         // Make the info tab
160         String helpSource = "/" + StraightModel.class.getPackage().getName().replace('.', '/') + "/IDMPlus.html";
161         URL page = StraightModel.class.getResource(helpSource);
162         if (page != null)
163         {
164             try
165             {
166                 HTMLPanel htmlPanel = new HTMLPanel(page);
167                 result.getPanel().getTabbedPane().addTab("info", new JScrollPane(htmlPanel));
168             }
169             catch (IOException exception)
170             {
171                 exception.printStackTrace();
172             }
173         }
174 
175         // Make the tab with the plots
176         AbstractProperty<?> output = new CompoundProperty("", "", this.properties, false, 0).findByShortName("Output");
177         if (null == output)
178         {
179             throw new Error("Cannot find output properties");
180         }
181         ArrayList<BooleanProperty> graphs = new ArrayList<BooleanProperty>();
182         if (output instanceof CompoundProperty)
183         {
184             CompoundProperty outputProperties = (CompoundProperty) output;
185             for (AbstractProperty<?> ap : outputProperties.getValue())
186             {
187                 if (ap instanceof BooleanProperty)
188                 {
189                     BooleanProperty bp = (BooleanProperty) ap;
190                     if (bp.getValue())
191                     {
192                         graphs.add(bp);
193                     }
194                 }
195             }
196         }
197         else
198         {
199             throw new Error("output properties should be compound");
200         }
201         int graphCount = graphs.size();
202         int columns = (int) Math.ceil(Math.sqrt(graphCount));
203         int rows = 0 == columns ? 0 : (int) Math.ceil(graphCount * 1.0 / columns);
204         TablePanel charts = new TablePanel(columns, rows);
205         result.getPanel().getTabbedPane().addTab("statistics", charts);
206 
207         for (int i = 0; i < graphCount; i++)
208         {
209             String graphName = graphs.get(i).getShortName();
210             Container container = null;
211             LaneBasedGTUSampler graph;
212             if (graphName.contains("Trajectories"))
213             {
214                 TrajectoryPlot tp =
215                     new TrajectoryPlot("TrajectoryPlot", new DoubleScalar.Rel<TimeUnit>(0.5, TimeUnit.SECOND), model
216                         .getMinimumDistance(), model.getMaximumDistance());
217                 tp.setTitle("Trajectory Graph");
218                 tp.setExtendedState(Frame.MAXIMIZED_BOTH);
219                 graph = tp;
220                 container = tp.getContentPane();
221             }
222             else
223             {
224                 ContourPlot cp;
225                 if (graphName.contains("Density"))
226                 {
227                     cp = new DensityContourPlot("DensityPlot", model.getMinimumDistance(), model.getMaximumDistance());
228                     cp.setTitle("Density Contour Graph");
229                 }
230                 else if (graphName.contains("Speed"))
231                 {
232                     cp = new SpeedContourPlot("SpeedPlot", model.getMinimumDistance(), model.getMaximumDistance());
233                     cp.setTitle("Speed Contour Graph");
234                 }
235                 else if (graphName.contains("Flow"))
236                 {
237                     cp = new FlowContourPlot("FlowPlot", model.getMinimumDistance(), model.getMaximumDistance());
238                     cp.setTitle("Flow Contour Graph");
239                 }
240                 else if (graphName.contains("Acceleration"))
241                 {
242                     cp =
243                         new AccelerationContourPlot("AccelerationPlot", model.getMinimumDistance(), model
244                             .getMaximumDistance());
245                     cp.setTitle("Acceleration Contour Graph");
246                 }
247                 else
248                 {
249                     throw new Error("Unhandled type of contourplot: " + graphName);
250                 }
251                 graph = cp;
252                 container = cp.getContentPane();
253             }
254             // Add the container to the matrix
255             charts.setCell(container, i % columns, i / columns);
256             model.getPlots().add(graph);
257         }
258         return result;
259     }
260 
261     /** {@inheritDoc} */
262     @Override
263     public final String shortName()
264     {
265         return "Straight lane";
266     }
267 
268     /** {@inheritDoc} */
269     @Override
270     public final String description()
271     {
272         return "<html><h1>Simulation of a straight one-lane road with opening bridge</H1>"
273             + "Simulation of a single lane road of 5 km length. Vehicles are generated at a constant rate of "
274             + "1500 veh/hour. At time 300s a blockade is inserted at position 4km; this blockade is removed at "
275             + "time 420s. This blockade simulates a bridge opening.<br/>"
276             + "The blockade causes a traffic jam that slowly dissolves after the blockade is removed.<br />"
277             + "Selected trajectory and contour plots are generated during the simulation.</html>";
278     }
279 
280     /** {@inheritDoc} */
281     @Override
282     public final ArrayList<AbstractProperty<?>> getProperties()
283     {
284         return new ArrayList<AbstractProperty<?>>(this.properties);
285     }
286 
287 }
288 
289 /**
290  * Simulate a single lane road of 5 km length. Vehicles are generated at a constant rate of 1500 veh/hour. At time 300s a
291  * blockade is inserted at position 4 km; this blockade is removed at time 500s. The used car following algorithm is IDM+ <a
292  * href="http://opentrafficsim.org/downloads/MOTUS%20reference.pdf"><i>Integrated Lane Change Model with Relaxation and
293  * Synchronization</i>, by Wouter J. Schakel, Victor L. Knoop and Bart van Arem, 2012</a>. <br>
294  * Output is a set of block charts:
295  * <ul>
296  * <li>Traffic density</li>
297  * <li>Speed</li>
298  * <li>Flow</li>
299  * <li>Acceleration</li>
300  * </ul>
301  * All these graphs display simulation time along the horizontal axis and distance along the road along the vertical axis.
302  * <p>
303  * Copyright (c) 2013-2014 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
304  * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
305  * <p>
306  * @version Aug 1, 2014 <br>
307  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
308  */
309 class StraightModel implements OTSModelInterface
310 {
311     /** */
312     private static final long serialVersionUID = 20140815L;
313 
314     /** the simulator. */
315     private OTSDEVSSimulatorInterface simulator;
316 
317     /** the headway (inter-vehicle time). */
318     private DoubleScalar.Rel<TimeUnit> headway;
319 
320     /** number of cars created. */
321     private int carsCreated = 0;
322 
323     /** the car following model, e.g. IDM Plus for cars. */
324     private GTUFollowingModel carFollowingModelCars;
325 
326     /** the car following model, e.g. IDM Plus for trucks. */
327     private GTUFollowingModel carFollowingModelTrucks;
328 
329     /** The probability that the next generated GTU is a passenger car. */
330     private double carProbability;
331 
332     /** cars in the model. */
333     private ArrayList<Car<Integer>> cars = new ArrayList<Car<Integer>>();
334 
335     /** The blocking car. */
336     private Car<Integer> block = null;
337 
338     /** minimum distance. */
339     private DoubleScalar.Rel<LengthUnit> minimumDistance = new DoubleScalar.Rel<LengthUnit>(0, LengthUnit.METER);
340 
341     /** maximum distance. */
342     private DoubleScalar.Rel<LengthUnit> maximumDistance = new DoubleScalar.Rel<LengthUnit>(5000, LengthUnit.METER);
343 
344     /** The Lane that contains the simulated Cars. */
345     private Lane lane;
346 
347     /** the speed limit. */
348     private DoubleScalar.Abs<SpeedUnit> speedLimit = new DoubleScalar.Abs<SpeedUnit>(100, SpeedUnit.KM_PER_HOUR);
349 
350     /** the contour plots. */
351     private ArrayList<LaneBasedGTUSampler> plots = new ArrayList<LaneBasedGTUSampler>();
352 
353     /** User settable properties. */
354     private ArrayList<AbstractProperty<?>> properties = null;
355 
356     /** The random number generator used to decide what kind of GTU to generate. */
357     private Random randomGenerator = new Random(12345);
358 
359     /**
360      * @param properties the user settable properties
361      */
362     public StraightModel(final ArrayList<AbstractProperty<?>> properties)
363     {
364         this.properties = properties;
365     }
366 
367     /** {@inheritDoc} */
368     @Override
369     public final void constructModel(
370         final SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> theSimulator)
371         throws SimRuntimeException, RemoteException
372     {
373         this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
374         Node from = new Node("From", new Coordinate(getMinimumDistance().getSI(), 0, 0));
375         Node to = new Node("To", new Coordinate(getMaximumDistance().getSI(), 0, 0));
376         try
377         {
378             LaneType<String> laneType = new LaneType<String>("CarLane");
379             this.lane = LaneFactory.makeLane("Lane", from, to, null, laneType, this.simulator);
380             String carFollowingModelName = null;
381             CompoundProperty propertyContainer = new CompoundProperty("", "", this.properties, false, 0);
382             AbstractProperty<?> cfmp = propertyContainer.findByShortName("Car following model");
383             if (null == cfmp)
384             {
385                 throw new Error("Cannot find \"Car following model\" property");
386             }
387             if (cfmp instanceof SelectionProperty)
388             {
389                 carFollowingModelName = ((SelectionProperty) cfmp).getValue();
390             }
391             else
392             {
393                 throw new Error("\"Car following model\" property has wrong type");
394             }
395             Iterator<AbstractProperty<ArrayList<AbstractProperty<?>>>> iterator =
396                 new CompoundProperty("", "", this.properties, false, 0).iterator();
397             while (iterator.hasNext())
398             {
399                 AbstractProperty<?> ap = iterator.next();
400                 if (ap instanceof SelectionProperty)
401                 {
402                     SelectionProperty sp = (SelectionProperty) ap;
403                     if ("Car following model".equals(sp.getShortName()))
404                     {
405                         if ("Car following model".equals(sp.getShortName()))
406                         {
407                             carFollowingModelName = sp.getValue();
408                         }
409                     }
410                 }
411                 else if (ap instanceof ProbabilityDistributionProperty)
412                 {
413                     ProbabilityDistributionProperty pdp = (ProbabilityDistributionProperty) ap;
414                     String modelName = ap.getShortName();
415                     if (modelName.equals("Traffic composition"))
416                     {
417                         this.carProbability = pdp.getValue()[0];
418                     }
419                 }
420                 else if (ap instanceof CompoundProperty)
421                 {
422                     CompoundProperty cp = (CompoundProperty) ap;
423                     if (ap.getShortName().equals("Output"))
424                     {
425                         continue; // Output settings are handled elsewhere
426                     }
427                     if (ap.getShortName().contains("IDM"))
428                     {
429                         DoubleScalar.Abs<AccelerationUnit> a = IDMPropertySet.getA(cp);
430                         DoubleScalar.Abs<AccelerationUnit> b = IDMPropertySet.getB(cp);
431                         DoubleScalar.Rel<LengthUnit> s0 = IDMPropertySet.getS0(cp);
432                         DoubleScalar.Rel<TimeUnit> tSafe = IDMPropertySet.getTSafe(cp);
433                         GTUFollowingModel gtuFollowingModel = null;
434                         if (carFollowingModelName.equals("IDM"))
435                         {
436                             gtuFollowingModel = new IDM(a, b, s0, tSafe, 1.0);
437                         }
438                         else if (carFollowingModelName.equals("IDM+"))
439                         {
440                             gtuFollowingModel = new IDMPlus(a, b, s0, tSafe, 1.0);
441                         }
442                         else
443                         {
444                             throw new Error("Unknown gtu following model: " + carFollowingModelName);
445                         }
446                         if (ap.getShortName().contains(" Car "))
447                         {
448                             this.carFollowingModelCars = gtuFollowingModel;
449                         }
450                         else if (ap.getShortName().contains(" Truck "))
451                         {
452                             this.carFollowingModelTrucks = gtuFollowingModel;
453                         }
454                         else
455                         {
456                             throw new Error("Cannot determine gtu type for " + ap.getShortName());
457                         }
458                         /*
459                          * System.out.println("Created " + carFollowingModelName + " for " + p.getShortName());
460                          * System.out.println("a: " + a); System.out.println("b: " + b); System.out.println("s0: " + s0);
461                          * System.out.println("tSafe: " + tSafe);
462                          */
463                     }
464                 }
465             }
466             // 1500 [veh / hour] == 2.4s headway
467             this.headway = new DoubleScalar.Rel<TimeUnit>(3600.0 / 1500.0, TimeUnit.SECOND);
468             // Schedule creation of the first car (it will re-schedule itself one headway later, etc.).
469             this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(0.0, TimeUnit.SECOND), this, this, "generateCar",
470                 null);
471             // Create a block at t = 5 minutes
472             this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(300, TimeUnit.SECOND), this, this, "createBlock",
473                 null);
474             // Remove the block at t = 7 minutes
475             this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(420, TimeUnit.SECOND), this, this, "removeBlock",
476                 null);
477             // Schedule regular updates of the graph
478             for (int t = 1; t <= 1800; t++)
479             {
480                 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(t - 0.001, TimeUnit.SECOND), this, this,
481                     "drawGraphs", null);
482             }
483         }
484         catch (RemoteException | SimRuntimeException | NamingException | NetworkException exception)
485         {
486             exception.printStackTrace();
487         }
488     }
489 
490     /**
491      * Add one movement step of one Car to all contour plots.
492      * @param car Car
493      * @throws RemoteException on communications failure
494      * @throws NetworkException on network-related inconsistency
495      */
496     protected final void addToContourPlots(final Car<?> car) throws RemoteException, NetworkException
497     {
498         for (LaneBasedGTUSampler plot : this.plots)
499         {
500             plot.addData(car);
501         }
502     }
503 
504     /**
505      * Notify the contour plots that the underlying data has changed.
506      */
507     protected final void drawGraphs()
508     {
509         for (LaneBasedGTUSampler plot : this.plots)
510         {
511             plot.reGraph();
512         }
513     }
514 
515     /**
516      * Set up the block.
517      * @throws RemoteException on communications failure
518      */
519     protected final void createBlock() throws RemoteException
520     {
521         DoubleScalar.Rel<LengthUnit> initialPosition = new DoubleScalar.Rel<LengthUnit>(4000, LengthUnit.METER);
522         Map<Lane, DoubleScalar.Rel<LengthUnit>> initialPositions = new HashMap<Lane, DoubleScalar.Rel<LengthUnit>>();
523         initialPositions.put(this.lane, initialPosition);
524         try
525         {
526             this.block =
527                 new IDMCar(999999, null, this.simulator, this.carFollowingModelCars, new DoubleScalar.Rel<LengthUnit>(4,
528                     LengthUnit.METER), this.simulator.getSimulatorTime().get(), initialPositions,
529                     new DoubleScalar.Abs<SpeedUnit>(0, SpeedUnit.KM_PER_HOUR));
530         }
531         catch (RemoteException | SimRuntimeException | NamingException | NetworkException exception)
532         {
533             exception.printStackTrace();
534         }
535     }
536 
537     /**
538      * Remove the block.
539      */
540     protected final void removeBlock()
541     {
542         this.block = null;
543     }
544 
545     /**
546      * Generate cars at a fixed rate (implemented by re-scheduling this method).
547      */
548     protected final void generateCar()
549     {
550         boolean generateTruck = this.randomGenerator.nextDouble() > this.carProbability;
551         DoubleScalar.Rel<LengthUnit> initialPosition = new DoubleScalar.Rel<LengthUnit>(0, LengthUnit.METER);
552         DoubleScalar.Abs<SpeedUnit> initialSpeed = new DoubleScalar.Abs<SpeedUnit>(100, SpeedUnit.KM_PER_HOUR);
553         Map<Lane, DoubleScalar.Rel<LengthUnit>> initialPositions = new HashMap<Lane, DoubleScalar.Rel<LengthUnit>>();
554         initialPositions.put(this.lane, initialPosition);
555         try
556         {
557             DoubleScalar.Rel<LengthUnit> vehicleLength =
558                 new DoubleScalar.Rel<LengthUnit>(generateTruck ? 15 : 4, LengthUnit.METER);
559             IDMCar car =
560                 new IDMCar(++this.carsCreated, null, this.simulator, generateTruck ? this.carFollowingModelTrucks
561                     : this.carFollowingModelCars, vehicleLength, this.simulator.getSimulatorTime().get(), initialPositions,
562                     initialSpeed);
563             this.cars.add(0, car);
564             this.simulator.scheduleEventRel(this.headway, this, this, "generateCar", null);
565         }
566         catch (RemoteException | SimRuntimeException | NamingException | NetworkException exception)
567         {
568             exception.printStackTrace();
569         }
570     }
571 
572     /** {@inheritDoc} */
573     @Override
574     public final SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> getSimulator()
575         throws RemoteException
576     {
577         return this.simulator;
578     }
579 
580     /**
581      * @return contourPlots
582      */
583     public final ArrayList<LaneBasedGTUSampler> getPlots()
584     {
585         return this.plots;
586     }
587 
588     /**
589      * @return minimumDistance
590      */
591     public final DoubleScalar.Rel<LengthUnit> getMinimumDistance()
592     {
593         return this.minimumDistance;
594     }
595 
596     /**
597      * @return maximumDistance
598      */
599     public final DoubleScalar.Rel<LengthUnit> getMaximumDistance()
600     {
601         return this.maximumDistance;
602     }
603 
604     /** Inner class IDMCar. */
605     protected class IDMCar extends Car<Integer>
606     {
607         /** */
608         private static final long serialVersionUID = 20141030L;
609 
610         /**
611          * Create a new IDMCar.
612          * @param id integer; the id of the new IDMCar
613          * @param gtuType GTUType&lt;String&gt;; the type of the GTU
614          * @param simulator OTSDEVSSimulator; the simulator that runs the new IDMCar
615          * @param carFollowingModel CarFollowingModel; the car following model of the new IDMCar
616          * @param vehicleLength DoubleScalar.Rel&lt;LengthUnit&gt;; the length of the new IDMCar
617          * @param initialTime DoubleScalar.Abs&lt;TimeUnit&gt;; the time of first evaluation of the new IDMCar
618          * @param initialLongitudinalPositions Map&lt;Lane, DoubleScalar.Rel&lt;LengthUnit&gt;&gt;; the initial lane positions
619          *            of the new IDMCar
620          * @param initialSpeed DoubleScalar.Abs&lt;SpeedUnit&gt;; the initial speed of the new IDMCar
621          * @throws NamingException when the animation cannot be created.
622          * @throws RemoteException when the simulator cannot be reached.
623          * @throws NetworkException when the GTU cannot be placed on the given lane.
624          * @throws SimRuntimeException when the move method cannot be scheduled.
625          */
626         @SuppressWarnings("checkstyle:parameternumber")
627         public IDMCar(final int id, final GTUType<String> gtuType, final OTSDEVSSimulatorInterface simulator,
628             final GTUFollowingModel carFollowingModel, final DoubleScalar.Rel<LengthUnit> vehicleLength,
629             final DoubleScalar.Abs<TimeUnit> initialTime,
630             final Map<Lane, DoubleScalar.Rel<LengthUnit>> initialLongitudinalPositions,
631             final DoubleScalar.Abs<SpeedUnit> initialSpeed) throws RemoteException, NamingException, NetworkException,
632             SimRuntimeException
633         {
634             super(id, gtuType, carFollowingModel, initialLongitudinalPositions, initialSpeed, vehicleLength,
635                 new DoubleScalar.Rel<LengthUnit>(1.8, LengthUnit.METER), new DoubleScalar.Abs<SpeedUnit>(200,
636                     SpeedUnit.KM_PER_HOUR), simulator);
637             try
638             {
639                 simulator.scheduleEventAbs(simulator.getSimulatorTime(), this, this, "move", null);
640             }
641             catch (SimRuntimeException exception)
642             {
643                 exception.printStackTrace();
644             }
645         }
646 
647         /**
648          * @throws RemoteException RemoteException
649          * @throws NamingException on ???
650          * @throws NetworkException on network inconsistency
651          * @throws SimRuntimeException on ??
652          */
653         protected final void move() throws RemoteException, NamingException, NetworkException, SimRuntimeException
654         {
655             // System.out.println("move " + getId());
656             if (this == StraightModel.this.block)
657             {
658                 return;
659             }
660             if (position(StraightModel.this.lane, getFront()).getSI() > getMaximumDistance().getSI())
661             {
662                 StraightModel.this.cars.remove(this);
663                 return;
664             }
665             Collection<Car<Integer>> leaders = new ArrayList<Car<Integer>>();
666             // FIXME: there should be a much easier way to obtain the leader; we should not have to maintain our own
667             // list
668             int carIndex = StraightModel.this.cars.indexOf(this);
669             if (carIndex < StraightModel.this.cars.size() - 1)
670             {
671                 leaders.add(StraightModel.this.cars.get(carIndex + 1));
672             }
673             GTUFollowingModelResult cfmr =
674                 getGTUFollowingModel().computeAcceleration(this, leaders, StraightModel.this.speedLimit);
675             if (null != StraightModel.this.block)
676             {
677                 leaders.clear();
678                 leaders.add(StraightModel.this.block);
679                 GTUFollowingModelResult blockCFMR =
680                     getGTUFollowingModel().computeAcceleration(this, leaders, StraightModel.this.speedLimit);
681                 if (blockCFMR.getAcceleration().getSI() < cfmr.getAcceleration().getSI()
682                     && blockCFMR.getAcceleration().getSI() >= -5)
683                 {
684                     cfmr = blockCFMR;
685                 }
686             }
687             setState(cfmr);
688             // Add the movement of this Car to the contour plots
689             addToContourPlots(this);
690             // Schedule the next evaluation of this car
691             getSimulator().scheduleEventRel(new DoubleScalar.Rel<TimeUnit>(0.5, TimeUnit.SECOND), this, this, "move", null);
692         }
693     }
694 }