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