1 package org.opentrafficsim.demo.carFollowing;
2
3 import java.awt.Frame;
4 import java.awt.geom.Rectangle2D;
5 import java.rmi.RemoteException;
6 import java.util.ArrayList;
7 import java.util.LinkedHashMap;
8 import java.util.Map;
9 import java.util.Random;
10
11 import javax.naming.NamingException;
12 import javax.swing.JPanel;
13 import javax.swing.SwingUtilities;
14
15 import nl.tudelft.simulation.dsol.SimRuntimeException;
16 import nl.tudelft.simulation.dsol.gui.swing.TablePanel;
17 import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
18
19 import org.djunits.unit.TimeUnit;
20 import org.djunits.value.vdouble.scalar.DoubleScalar;
21 import org.opentrafficsim.core.OTS_SCALAR;
22 import org.opentrafficsim.core.dsol.OTSDEVSSimulatorInterface;
23 import org.opentrafficsim.core.dsol.OTSModelInterface;
24 import org.opentrafficsim.core.dsol.OTSSimTimeDouble;
25 import org.opentrafficsim.core.geometry.OTSGeometryException;
26 import org.opentrafficsim.core.geometry.OTSPoint3D;
27 import org.opentrafficsim.core.gtu.GTUException;
28 import org.opentrafficsim.core.gtu.GTUType;
29 import org.opentrafficsim.core.gtu.animation.GTUColorer;
30 import org.opentrafficsim.core.network.LongitudinalDirectionality;
31 import org.opentrafficsim.core.network.NetworkException;
32 import org.opentrafficsim.core.network.OTSNode;
33 import org.opentrafficsim.core.network.route.CompleteRoute;
34 import org.opentrafficsim.graphs.FundamentalDiagram;
35 import org.opentrafficsim.road.car.LaneBasedIndividualCar;
36 import org.opentrafficsim.road.gtu.animation.DefaultCarAnimation;
37 import org.opentrafficsim.road.gtu.following.GTUFollowingModel;
38 import org.opentrafficsim.road.gtu.following.IDM;
39 import org.opentrafficsim.road.gtu.following.IDMPlus;
40 import org.opentrafficsim.road.gtu.lane.changing.AbstractLaneChangeModel;
41 import org.opentrafficsim.road.gtu.lane.changing.Egoistic;
42 import org.opentrafficsim.road.network.factory.LaneFactory;
43 import org.opentrafficsim.road.network.lane.CrossSectionLink;
44 import org.opentrafficsim.road.network.lane.Lane;
45 import org.opentrafficsim.road.network.lane.LaneType;
46 import org.opentrafficsim.road.network.lane.Sensor;
47 import org.opentrafficsim.road.network.lane.SinkSensor;
48 import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
49 import org.opentrafficsim.road.network.route.CompleteLaneBasedRouteNavigator;
50 import org.opentrafficsim.simulationengine.AbstractWrappableAnimation;
51 import org.opentrafficsim.simulationengine.properties.AbstractProperty;
52 import org.opentrafficsim.simulationengine.properties.ProbabilityDistributionProperty;
53 import org.opentrafficsim.simulationengine.properties.PropertyException;
54 import org.opentrafficsim.simulationengine.properties.SelectionProperty;
55
56
57
58
59
60
61
62
63
64
65
66 public class FundamentalDiagrams extends AbstractWrappableAnimation
67 {
68
69 private FundamentalDiagramPlotsModel model;
70
71
72 public FundamentalDiagrams()
73 {
74 try
75 {
76 this.properties.add(new SelectionProperty("Car following model",
77 "<html>The car following model determines "
78 + "the acceleration that a vehicle will make taking into account nearby vehicles, "
79 + "infrastructural restrictions (e.g. speed limit, curvature of the road) "
80 + "capabilities of the vehicle and personality of the driver.</html>", new String[]{"IDM", "IDM+"},
81 1, false, 500));
82 this.properties.add(new ProbabilityDistributionProperty("Traffic composition",
83 "<html>Mix of passenger cars and trucks</html>", new String[]{"passenger car", "truck"}, new Double[]{
84 0.8, 0.2}, false, 10));
85 }
86 catch (PropertyException exception)
87 {
88 exception.printStackTrace();
89 }
90 }
91
92
93 @Override
94 public final void stopTimersThreads()
95 {
96 super.stopTimersThreads();
97 this.model = null;
98 }
99
100
101
102
103
104
105 public static void main(final String[] args) throws SimRuntimeException
106 {
107
108 SwingUtilities.invokeLater(new Runnable()
109 {
110 @Override
111 public void run()
112 {
113 try
114 {
115 FundamentalDiagrams fundamentalDiagrams = new FundamentalDiagrams();
116 fundamentalDiagrams.buildAnimator(new Time.Abs(0.0, SECOND), new Time.Rel(0.0, SECOND),
117 new Time.Rel(3600.0, SECOND), fundamentalDiagrams.getProperties(), null, true);
118 }
119 catch (SimRuntimeException | NamingException exception)
120 {
121 exception.printStackTrace();
122 }
123 }
124 });
125 }
126
127
128 @Override
129 protected final OTSModelInterface makeModel(final GTUColorer colorer)
130 {
131 this.model = new FundamentalDiagramPlotsModel(this.savedUserModifiedProperties, colorer);
132 return this.model;
133 }
134
135
136 @Override
137 protected final Rectangle2D.Double makeAnimationRectangle()
138 {
139 return new Rectangle2D.Double(0, -100, 5000, 200);
140 }
141
142
143 @Override
144 protected final JPanel makeCharts()
145 {
146 final int panelsPerRow = 3;
147 TablePanel charts = new TablePanel(4, panelsPerRow);
148 for (int plotNumber = 0; plotNumber < 10; plotNumber++)
149 {
150 Length.Rel detectorLocation = new Length.Rel(400 + 500 * plotNumber, METER);
151 FundamentalDiagram fd;
152 try
153 {
154 fd =
155 new FundamentalDiagram("Fundamental Diagram at " + detectorLocation.getSI() + "m", new Time.Rel(1,
156 MINUTE), this.model.getLane(), detectorLocation);
157 fd.setTitle("Density Contour Graph");
158 fd.setExtendedState(Frame.MAXIMIZED_BOTH);
159 this.model.getFundamentalDiagrams().add(fd);
160 charts.setCell(fd.getContentPane(), plotNumber / panelsPerRow, plotNumber % panelsPerRow);
161 }
162 catch (NetworkException exception)
163 {
164 exception.printStackTrace();
165 }
166 }
167 return charts;
168 }
169
170
171 @Override
172 public final String shortName()
173 {
174 return "Fundamental Diagrams";
175 }
176
177
178 @Override
179 public final String description()
180 {
181 return "<html><h1>Fundamental Diagram Plots</H1>"
182 + "Simulation of a single lane road of 5 km length. Vechicles are generated at a constant rate of "
183 + "1500 veh/hour. At time 300s a blockade is inserted at position 4km; this blockade is removed at time "
184 + "500s. This blockade simulates a bridge opening.<br>"
185 + "The blockade causes a traffic jam that slowly dissolves after the blockade is removed.<br />"
186 + "Output is a set of Diagrams that plot observed density, flow and speed plots against each other.</html>";
187 }
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203 class FundamentalDiagramPlotsModel implements OTSModelInterface, OTS_SCALAR
204 {
205
206 private static final long serialVersionUID = 20140820L;
207
208
209 private OTSDEVSSimulatorInterface simulator;
210
211
212 private Time.Rel headway;
213
214
215 private int carsCreated = 0;
216
217
218 private GTUType gtuType = GTUType.makeGTUType("Car");
219
220
221 private GTUFollowingModel carFollowingModelCars;
222
223
224 private GTUFollowingModel carFollowingModelTrucks;
225
226
227 private double carProbability;
228
229
230 private AbstractLaneChangeModel laneChangeModel = new Egoistic();
231
232
233 private LaneBasedIndividualCar block = null;
234
235
236 private Length.Rel minimumDistance = new Length.Rel(0, METER);
237
238
239 private Length.Rel maximumDistance = new Length.Rel(5000, METER);
240
241
242 private Lane lane;
243
244
245 private Speed.Abs speedLimit = new Speed.Abs(100, KM_PER_HOUR);
246
247
248 private ArrayList<FundamentalDiagram> fundamentalDiagrams = new ArrayList<FundamentalDiagram>();
249
250
251 private ArrayList<AbstractProperty<?>> properties = null;
252
253
254 private Random randomGenerator = new Random(12345);
255
256
257 private final GTUColorer gtuColorer;
258
259
260
261
262
263 public FundamentalDiagramPlotsModel(final ArrayList<AbstractProperty<?>> properties, final GTUColorer gtuColorer)
264 {
265 this.properties = properties;
266 this.gtuColorer = gtuColorer;
267 }
268
269
270 @Override
271 public final
272 void
273 constructModel(
274 final SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble> theSimulator)
275 throws SimRuntimeException, RemoteException
276 {
277 this.simulator = (OTSDEVSSimulatorInterface) theSimulator;
278 OTSNode from = new OTSNode("From", new OTSPoint3D(getMinimumDistance().getSI(), 0, 0));
279 OTSNode to = new OTSNode("To", new OTSPoint3D(getMaximumDistance().getSI(), 0, 0));
280 OTSNode end = new OTSNode("End", new OTSPoint3D(getMaximumDistance().getSI() + 50.0, 0, 0));
281 LaneType laneType = new LaneType("CarLane");
282 laneType.addCompatibility(this.gtuType);
283 try
284 {
285 this.lane = LaneFactory.makeLane("Lane", from, to, null, laneType, this.speedLimit, this.simulator);
286 CrossSectionLink endLink = LaneFactory.makeLink("endLink", to, end, null);
287
288 Lane sinkLane =
289 new Lane(endLink, "sinkLane", this.lane.getLateralCenterPosition(1.0), this.lane
290 .getLateralCenterPosition(1.0), this.lane.getWidth(1.0), this.lane.getWidth(1.0), laneType,
291 LongitudinalDirectionality.FORWARD, this.speedLimit, new OvertakingConditions.None());
292 Sensor sensor = new SinkSensor(sinkLane, new Length.Rel(10.0, METER), this.simulator);
293 sinkLane.addSensor(sensor, GTUType.ALL);
294 }
295 catch (NamingException | NetworkException | OTSGeometryException exception)
296 {
297 exception.printStackTrace();
298 }
299
300
301
302 for (AbstractProperty<?> p : this.properties)
303 {
304 if (p instanceof SelectionProperty)
305 {
306 SelectionProperty sp = (SelectionProperty) p;
307 if ("Car following model".equals(sp.getShortName()))
308 {
309 String modelName = sp.getValue();
310 if (modelName.equals("IDM"))
311 {
312 this.carFollowingModelCars =
313 new IDM(new Acceleration.Abs(1, METER_PER_SECOND_2), new Acceleration.Abs(1.5,
314 METER_PER_SECOND_2), new Length.Rel(2, METER), new Time.Rel(1, SECOND), 1d);
315 this.carFollowingModelTrucks =
316 new IDM(new Acceleration.Abs(0.5, METER_PER_SECOND_2), new Acceleration.Abs(1.5,
317 METER_PER_SECOND_2), new Length.Rel(2, METER), new Time.Rel(1, SECOND), 1d);
318 }
319 else if (modelName.equals("IDM+"))
320 {
321 this.carFollowingModelCars =
322 new IDMPlus(new Acceleration.Abs(1, METER_PER_SECOND_2), new Acceleration.Abs(1.5,
323 METER_PER_SECOND_2), new Length.Rel(2, METER), new Time.Rel(1, SECOND), 1d);
324 this.carFollowingModelTrucks =
325 new IDMPlus(new Acceleration.Abs(0.5, METER_PER_SECOND_2), new Acceleration.Abs(1.5,
326 METER_PER_SECOND_2), new Length.Rel(2, METER), new Time.Rel(1, SECOND), 1d);
327 }
328 else
329 {
330 throw new Error("Car following model " + modelName + " not implemented");
331 }
332 }
333 else
334 {
335 throw new Error("Unhandled SelectionProperty " + p.getShortName());
336 }
337 }
338 else if (p instanceof ProbabilityDistributionProperty)
339 {
340 ProbabilityDistributionProperty pdp = (ProbabilityDistributionProperty) p;
341 String modelName = p.getShortName();
342 if (modelName.equals("Traffic composition"))
343 {
344 this.carProbability = pdp.getValue()[0];
345 }
346 else
347 {
348 throw new Error("Unhandled ProbabilityDistributionProperty " + p.getShortName());
349 }
350 }
351 else
352 {
353 throw new Error("Unhandled property: " + p);
354 }
355 }
356
357
358 this.headway = new Time.Rel(3600.0 / 1500.0, SECOND);
359
360 try
361 {
362
363 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(0.0, SECOND), this, this, "generateCar",
364 null);
365
366 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(300, SECOND), this, this, "createBlock",
367 null);
368
369 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(420, SECOND), this, this, "removeBlock",
370 null);
371
372 for (int t = 1; t <= 1800; t++)
373 {
374 this.simulator.scheduleEventAbs(new DoubleScalar.Abs<TimeUnit>(t - 0.001, SECOND), this, this,
375 "drawGraphs", null);
376 }
377 }
378 catch (SimRuntimeException exception)
379 {
380 exception.printStackTrace();
381 }
382 }
383
384
385
386
387
388 protected final void createBlock() throws RemoteException
389 {
390 Length.Rel initialPosition = new Length.Rel(4000, METER);
391 Map<Lane, Length.Rel> initialPositions = new LinkedHashMap<Lane, Length.Rel>();
392 initialPositions.put(this.getLane(), initialPosition);
393 try
394 {
395 this.block =
396 new LaneBasedIndividualCar("999999", this.gtuType, this.carFollowingModelCars,
397 this.laneChangeModel, initialPositions, new Speed.Abs(0, KM_PER_HOUR),
398 new Length.Rel(4, METER), new Length.Rel(1.8, METER), new Speed.Abs(0, KM_PER_HOUR),
399 new CompleteLaneBasedRouteNavigator(new CompleteRoute("")), this.simulator,
400 DefaultCarAnimation.class, this.gtuColorer);
401 }
402 catch (SimRuntimeException | NamingException | NetworkException | GTUException exception)
403 {
404 exception.printStackTrace();
405 }
406 }
407
408
409
410
411 protected final void removeBlock()
412 {
413 this.block.destroy();
414 this.block = null;
415 }
416
417
418
419
420 protected final void generateCar()
421 {
422 boolean generateTruck = this.randomGenerator.nextDouble() > this.carProbability;
423 Length.Rel initialPosition = new Length.Rel(0, METER);
424 Speed.Abs initialSpeed = new Speed.Abs(100, KM_PER_HOUR);
425 Map<Lane, Length.Rel> initialPositions = new LinkedHashMap<Lane, Length.Rel>();
426 initialPositions.put(this.getLane(), initialPosition);
427 try
428 {
429 Length.Rel vehicleLength = new Length.Rel(generateTruck ? 15 : 4, METER);
430 GTUFollowingModel gtuFollowingModel =
431 generateTruck ? this.carFollowingModelTrucks : this.carFollowingModelCars;
432 if (null == gtuFollowingModel)
433 {
434 throw new Error("gtuFollowingModel is null");
435 }
436 new LaneBasedIndividualCar("" + (++this.carsCreated), this.gtuType, generateTruck
437 ? this.carFollowingModelTrucks : this.carFollowingModelCars, this.laneChangeModel,
438 initialPositions, initialSpeed, vehicleLength, new Length.Rel(1.8, METER), new Speed.Abs(200,
439 KM_PER_HOUR), new CompleteLaneBasedRouteNavigator(new CompleteRoute("")), this.simulator,
440 DefaultCarAnimation.class, this.gtuColorer);
441 this.simulator.scheduleEventRel(this.headway, this, this, "generateCar", null);
442 }
443 catch (SimRuntimeException | NamingException | NetworkException | GTUException exception)
444 {
445 exception.printStackTrace();
446 }
447 }
448
449
450
451
452 protected final void drawGraphs()
453 {
454
455 for (FundamentalDiagram fd : this.fundamentalDiagrams)
456 {
457 fd.reGraph();
458 }
459 }
460
461
462 @Override
463 public final SimulatorInterface<DoubleScalar.Abs<TimeUnit>, DoubleScalar.Rel<TimeUnit>, OTSSimTimeDouble>
464 getSimulator() throws RemoteException
465 {
466 return null;
467 }
468
469
470
471
472 public final ArrayList<FundamentalDiagram> getFundamentalDiagrams()
473 {
474 return this.fundamentalDiagrams;
475 }
476
477
478
479
480 public final Length.Rel getMinimumDistance()
481 {
482 return this.minimumDistance;
483 }
484
485
486
487
488 public final Length.Rel getMaximumDistance()
489 {
490 return this.maximumDistance;
491 }
492
493
494
495
496 public Lane getLane()
497 {
498 return this.lane;
499 }
500 }
501 }