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